Logo for tanaschita.com

Building a draggable bottom sheet in SwiftUI

Learn how to build a draggable bottom sheet using presentation detents.

20 Apr 2026 · 5 min read

Some apps, such as Apple Maps or Google Maps, use a draggable bottom sheet to let users switch between the main content, for example a map, and additional information presented in a sheet.

In this article, we'll look at how to build a draggable bottom sheet that works together with a scroll view and still allows interaction with the underlying content.

Example of a draggable bottom sheet.
Example of a draggable bottom sheet.

Let's jump in.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

Implementing the bottom sheet

To be more precise, what we'd like to achieve is:

  • the sheet has multiple states such as collapsed, medium and expanded
  • the sheet is not fully dismissable by user interaction
  • the user can interact with the contents of the underlying content such as a map
  • dragging the sheet works together with a scroll view used to display its content

We can implement the described behaviour by using SwiftUI's sheet combined with presentationDetents:

struct ContentView: View {
@State private var showingBottomSheet = true
var body: some View {
MapView()
.sheet(isPresented: $showingBottomSheet) {
ScrollView {
// Add content of the bottom sheet here.
}
.interactiveDismissDisabled()
.presentationDetents([.height(50), .medium, .large])
.presentationBackgroundInteraction(
.enabled(upThrough: .large)
)
}
}
}

Let's break this down.

Understanding detents

Detents define the different heights the sheet can snap to.

.presentationDetents([.height(50), .medium, .large])

In this example:

By combining these, we create a sheet that can move between multiple states depending on the user's interaction.

Controlling dismissal behavior

By default, sheets can be dismissed by dragging them down. In this case, we don't want that default behavior:

.interactiveDismissDisabled()

This ensures that the sheet stays visible and behaves more like a persistent UI element rather than a modal.

Enabling background interaction

One important aspect of the sheet is that the user can still interact with the underlying content, for example a map.

.presentationBackgroundInteraction(
.enabled(upThrough: .large)
)

This allows interaction with the content behind the sheet while it's not fully covering it.

Working with scroll views

To display content inside the sheet, we typically use a ScrollView.

SwiftUI automatically coordinates the scrolling behavior with the sheet’s dragging behavior:

  • when the scroll view is scrolled, it handles the gesture
  • when it reaches the top, dragging continues to move the sheet

This coordination is built into the system and does not require additional steps from our side.

Adding a drag indicator

To make the interaction more discoverable, we can show a drag indicator:

.presentationDragIndicator(.visible)

This provides a visual hint that the sheet can be dragged.

Limitations

One limitation of this approach is that the sheet is always presented above the entire view hierarchy.

This means it will also cover elements such as a tab bar. If more control over layering is required, for example to place content above the sheet, a custom implementation may be necessary.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

activitykit

widgetkit

swiftui

swift

ios

Getting started with Live Activities in SwiftUI

Build a public transport journey tracker for the Lock Screen and Dynamic Island with ActivityKit.

07 Sep 2026 · 7 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum