- name
- swiftui-ui-patterns
- description
- Best practices and example-driven guidance for building SwiftUI views and components. Use when creating or refactoring SwiftUI UI, designing tab architecture with TabView, composing screens, or needing component-specific patterns and examples.
# SwiftUI UI Patterns
## Quick start
Choose a track based on your goal:
### Existing project
- Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed).
- Find a nearby example in the repo with `rg "TabView\("` or similar, then read the closest SwiftUI view.
- Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies.
- Choose the relevant component reference from `references/components-index.md` and follow its guidance.
- Build the view with small, focused subviews and SwiftUI-native data flow.
### New project scaffolding
- Start with `references/app-scaffolding-wiring.md` to wire TabView + NavigationStack + sheets.
- Add a minimal `AppTab` and `RouterPath` based on the provided skeletons.
- Choose the next component reference based on the UI you need first (TabView, NavigationStack, Sheets).
- Expand the route and sheet enums as new screens are added.
## General rules to follow
- Use modern SwiftUI state (`@State`, `@Binding`, `@Observable`, `@Environment`) and avoid unnecessary view models.
- Prefer composition; keep views small and focused.
- 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
1. Define the view's state and its ownership location.
2. Identify dependencies to inject via `@Environment`.
3. Sketch the view hierarchy and extract repeated parts into subviews.
4. Implement async loading with `.task` and explicit state enum if needed.
5. Add accessibility labels or identifiers when the UI is interactive.
6. Validate with a build and update usage callsites if needed.
## Component references
Use `references/components-index.md` as the entry point. Each component reference should include:
- Intent and best-fit scenarios.
- Minimal usage pattern with local conventions.
- 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/<component>.md`.
- Keep it short and actionable; link to concrete files in the current repo.
- Update `references/components-index.md` with the new entry.
## Technique Map
- **Track-based workflow** — Existing project vs new scaffolding; because different entry points.
- **components-index.md as router** — Find component reference from index; because modular guidance.
- **app-scaffolding-wiring** — TabView + NavigationStack + sheets first; because structure before content.
- **.sheet(item:) over .sheet(isPresented:)** — Model-driven sheets; because avoids optional state bugs.
- **Sheet owns actions** — dismiss() internally; no forwarded onCancel/onConfirm; because single ownership.
- **Define state ownership first** — Before sketching hierarchy; because data flow drives structure.
- **@ViewBuilder let content** — For container views; because cleaner than closure-based.
## Technique Notes
References: components-index.md, app-scaffolding-wiring.md, component-specific refs. Use rg for existing patterns (TabView, etc.). Keep views small, state local, environment for shared deps. Add component refs to index when creating new.
---
## Prompt Architect Overlay
**Role Definition:** SwiftUI UI patterns guide. TabView, NavigationStack, sheets, list/detail, editor, settings. Example-driven. Composing screens, component patterns.
**Input Contract:** Accepts "how do I build X," new view, tab architecture, sheet pattern, or component need. Project context (existing or new). Target UI type.
**Output Contract:** Workflow steps. Component reference from index. Code pattern (sheet(item:), etc.). Pitfalls and performance notes. Path to existing examples in repo. Scaffolding skeleton if new project.
**Edge Cases & Fallbacks:** If component not in index→create references/<component>.md, update index. If legacy pattern→maintain only when editing legacy file. If form/settings→reference form patterns. If async loading→.task + explicit state enum.
Auf GitHub ansehen