From 4fb872727edb2a22d3acc9db57c631912cd0cfd5 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Thu, 8 Jan 2026 13:01:46 +0100 Subject: [PATCH] Document preferred SwiftUI sheet patterns Adds guidance on using `.sheet(item:)` over `.sheet(isPresented:)` for model-driven state, and recommends that sheets own their actions and handle dismissal internally. Includes code examples and best practices for sheet usage in SwiftUI. --- swiftui-ui-patterns/SKILL.md | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/swiftui-ui-patterns/SKILL.md b/swiftui-ui-patterns/SKILL.md index 9cd61e4..2383d7a 100644 --- a/swiftui-ui-patterns/SKILL.md +++ b/swiftui-ui-patterns/SKILL.md @@ -31,6 +31,7 @@ Choose a track based on your goal: - Use async/await with `.task` and explicit loading/error states. - Maintain existing legacy patterns only when editing legacy files. - Follow the project's formatter and style guide. +- **Sheets**: Prefer `.sheet(item:)` over `.sheet(isPresented:)` when state represents a selected model. Avoid `if let` inside a sheet body. Sheets should own their actions and call `dismiss()` internally instead of forwarding `onCancel`/`onConfirm` closures. ## Workflow for a new SwiftUI view @@ -49,6 +50,44 @@ Use `references/components-index.md` as the entry point. Each component referenc - Pitfalls and performance notes. - Paths to existing examples in the current repo. +## Sheet patterns + +### Item-driven sheet (preferred) + +```swift +@State private var selectedItem: Item? + +.sheet(item: $selectedItem) { item in + EditItemSheet(item: item) +} +``` + +### Sheet owns its actions + +```swift +struct EditItemSheet: View { + @Environment(\.dismiss) private var dismiss + @Environment(Store.self) private var store + + let item: Item + @State private var isSaving = false + + var body: some View { + VStack { + Button(isSaving ? "Saving…" : "Save") { + Task { await save() } + } + } + } + + private func save() async { + isSaving = true + await store.save(item) + dismiss() + } +} +``` + ## Adding a new component reference - Create `references/.md`.