SwiftUI Custom Bottom Sheet
A customizable bottom sheet modal in SwiftUI for presenting content interactively.
import SwiftUI
struct BottomSheetView: View {
@State private var showingSheet = false
var body: some View {
Button("Show Bottom Sheet") {
showingSheet = true
}
.sheet(isPresented: $showingSheet) {
CustomBottomSheetContent()
.presentationDetents([.medium, .large])
}
}
}
struct CustomBottomSheetContent: View {
var body: some View {
ScrollView {
VStack(spacing: 16) {
RoundedRectangle(cornerRadius: 4)
.frame(width: 40, height: 5)
.foregroundColor(.gray.opacity(0.5))
.padding(.top, 8)
Text("Custom Bottom Sheet")
.font(.title2)
.fontWeight(.bold)
Text("This is a fully customizable bottom sheet modal. You can adjust colors, fonts, and detent sizes to fit your app's design.")
.multilineTextAlignment(.center)
.padding(.horizontal)
Button(action: {}) {
Text("Primary Action")
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue)
.cornerRadius(12)
}
Button(action: {}) {
Text("Secondary Action")
.foregroundColor(.blue)
.padding()
.frame(maxWidth: .infinity)
.background(Color.blue.opacity(0.1))
.cornerRadius(12)
}
Spacer(minLength: 32)
}
.padding(.horizontal)
}
}
}
#Preview {
BottomSheetView()
}How It Works
The custom bottom sheet in SwiftUI leverages the .sheet() modifier and the .presentationDetents() API introduced in iOS 16. This allows developers to define specific heights (or detents) at which the bottom sheet can rest — typically .medium and .large. When a user interacts with the sheet, they can drag it between these states.
Inside the sheet content, a ScrollView ensures that the content remains scrollable when it exceeds the available screen space. The top handle — a small rounded rectangle — gives users a visual cue for dragging. Buttons and text are styled with padding and corner radii to create a clean, modern interface. The entire layout is wrapped in a VStack to organize content vertically.
Customization
| Parameter | Where to change | Example values |
|---|---|---|
| Sheet background color | In the background() modifier of the content |
.white, .blue.opacity(0.1) |
| Text color and font | In Text() and .foregroundColor() modifiers |
.black, .font(.title) |
| Button styles | Inside the Button() views |
Change background color, corner radius |
| Detent sizes | In .presentationDetents() |
[.medium], [.large] |
| Handle color | In the RoundedRectangle() view |
.gray, .black |
Accessibility Notes
Ensure buttons have descriptive labels and consider adding .accessibilityLabel() for screen readers. Use sufficient contrast between text and background colors to support readability.