Components / Gestures

Expanding cards

Cards that open into an immersive detail view, with shared geometry and a drag-to-dismiss gesture.

iOS 17+Swift 6MITView source
Expanding cards, 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 expanding-cards

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 selected: Story.ID?

HugsyExpandingCards(items: stories, selection: $selected) { story, expanded in
  VStack(alignment: .leading, spacing: 16) {
    Text(story.title).font(.largeTitle.bold())
    if expanded { Text(story.description) }
  }
  .padding(28)
  .frame(maxWidth: .infinity, maxHeight: .infinity)
  .background(story.color.gradient)
}

Supply Identifiable items and one content builder. The builder receives the item and its expanded state. Keep card IDs stable and unique. Place the component in a container with enough vertical room for the expanded content. It is an inline expanding surface, not a system modal sheet.

API reference

Expanding cards parameters
ParameterType & behaviorDefault
items[Item: Identifiable]

Your models, with stable and unique IDs.

Required
selectionBinding<Item.ID?>

The open card ID. Set nil to close it programmatically.

Required
cardHeightCGFloat

Collapsed height, clamped to at least 44 points.

180
expandedHeightCGFloat

Open height, clamped to at least the card height.

440
content(Item, Bool) -> Content

A view builder receiving the model and expanded state.

Required

Interaction

Tap a card to open its details. Drag downward to dismiss, or use the close button.

RestingExpandingOpenDraggingClosing

Accessibility

Native buttons expose card actions. Expanded content hides the underlying cards from VoiceOver. A labeled close button and Escape accessibility action provide alternatives to dragging. Reduce Motion removes spring interpolation.

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.