iOS & macOS DevelopmentDocumentedScanned

swiftui-ui-patterns

Best practices and example-driven guidance for building SwiftUI views and components.

Share:

Installation

npx clawhub@latest install swiftui-ui-patterns

View the full skill documentation and source below.

Documentation

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

  • Define the view's state and its ownership location.

  • Identify dependencies to inject via @Environment.

  • Sketch the view hierarchy and extract repeated parts into subviews.

  • Implement async loading with .task and explicit state enum if needed.

  • Add accessibility labels or identifiers when the UI is interactive.

  • 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)

    @State private var selectedItem: Item?
    
    .sheet(item: $selectedItem) { item in
        EditItemSheet(item: item)
    }

    Sheet owns its actions

    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.
    • Keep it short and actionable; link to concrete files in the current repo.
    • Update references/components-index.md with the new entry.