Components / Overlay

Morphing sheet

A draggable surface that interpolates its height and corner radius, then settles into a compact or expanded state.

iOS 17+Swift 6MITView source
Morphing sheet, rendered by SwiftUI on an iPhone simulator
Recorded in the iOS simulator

Real SwiftUI, captured on an iPhone 17 Pro simulator. Run the native gallery

Installation

Install the native Swift CLI, then add the component to your app.

Terminal
hugsy add morphing-sheet

Prefer to copy it yourself? Open the complete Swift file and add it to your iOS app target in Xcode. No package dependency is required.

Usage

SwiftUI
@State private var position: HugsySheetPosition = .compact

HugsyMorphingSheet(position: $position) { state in
  VStack(spacing: 20) {
    Text("Now playing").font(.headline)
    if state == .expanded { PlayerDetails() }
  }
  .padding(.horizontal, 24)
}

Bind HugsySheetPosition to your screen state. Supply compact and expanded heights and content that adapts to the current position. Dragging is limited to the handle so content can keep its own gestures. Use native .sheet presentation if your app requires a modal barrier.

API reference

Morphing sheet parameters
ParameterType & behaviorDefault
positionBinding<HugsySheetPosition>

Either .compact or .expanded. Drives the inline surface.

Required
compactHeightCGFloat

Collapsed height, clamped to at least 100 points.

200
expandedHeightCGFloat

Expanded height, at least 44 points above the compact height.

430
content(HugsySheetPosition) -> Content

Content that adapts to the current position.

Required

Interaction

Drag the handle upward to expand the surface. Tap the handle to toggle without dragging.

CompactDraggingExpandedSettling

Accessibility

The handle is a labeled native button. VoiceOver users can also adjust the surface with increment and decrement actions. Reduce Motion disables spring interpolation. This is an inline surface, not a replacement for the focus containment of a system sheet.

Test with VoiceOver, Dynamic Type, and Reduce Motion on a physical device before shipping. The gallery demonstrates the interaction, not every application-specific content state.