All skills
avdlee avatar

/swiftui-expert-skill

@1e522cf

Use when writing, reviewing, or refactoring SwiftUI code for iOS or macOS, including state and `@Observable` data flow, view composition, resizable layouts, safe areas, display scale, performance, lists, environment, localization, animation, Liquid Glass, and API migration. Also use for iPhone Duo, foldable, or large-display layouts (`NavigationSplitView` on large displays, two-column reflow, foldable grids, `ArrangementView`, `ReservedRegion`), hinge effects, vertical bars, `@State` initialization or synthesized-property diagnostics, `@ContentBuilder` ambiguity, `reorderable` drag/drop, custom `AsyncImage` `URLSession`, swipe actions outside List, item-bound `alert`/`confirmationDialog`, `ToolbarOverflowMenu`, `AnimatableValues`, Document APIs (`Document`/`DocumentReader`), and Instruments `.trace` capture or analysis.

Use this Skill: https://skilld.dev/gh/avdlee/swiftui-agent-skill/swiftui-expert-skill

This session only. Nothing lands on disk.

referencesmacos-scenes.md

≈2.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

macOS Scenes Reference

SwiftUI scene types for macOS apps — Settings, MenuBarExtra, WindowGroup, Window, UtilityWindow, and DocumentGroup. Covers macOS-only scenes and cross-platform scenes with macOS-specific behavior.

Table of Contents


Quick Lookup Table

API Availability macOS-Only? macOS-Specific Behavior
WindowGroup macOS 11.0+ No Multiple window instances, tabbed interface, automatic Window menu commands
Window macOS 13.0+ No App quits when sole window closes; adds itself to Windows menu
UtilityWindow macOS 15.0+ Yes Floating tool palette; receives FocusedValues from active main window
Settings macOS 11.0+ Yes Presents preferences window (Cmd+,)
MenuBarExtra macOS 13.0+ Yes Persistent icon/menu in the system menu bar
DocumentGroup macOS 11.0+ No Document-based menu bar commands (File > New/Open/Save); multiple document windows

Settings (macOS-only)

Presents the app's preferences window, accessible via Cmd+, or the app menu. SwiftUI automatically enables the Settings menu item and manages the window lifecycle.

Settings {
    TabView {
        Tab("General", systemImage: "gear") { GeneralSettingsView() }
        Tab("Advanced", systemImage: "star") { AdvancedSettingsView() }
    }
    .scenePadding()
    .frame(maxWidth: 350, minHeight: 100)
}

Use TabView with Tab items for multi-pane preferences. Each tab's content is typically a Form with @AppStorage-backed controls.

SettingsLink (macOS 14.0+)

A button that opens the Settings scene. Use for in-app navigation to preferences.

struct SidebarFooter: View {
    var body: some View {
        SettingsLink {
            Label("Preferences", systemImage: "gear")
        }
    }
}

openSettings environment action (macOS 14.0+)

Programmatically open (or bring to front) the Settings window.

struct OpenSettingsButton: View {
    @Environment(\.openSettings) private var openSettings

    var body: some View {
        Button("Open Settings") {
            openSettings()
        }
    }
}

MenuBarExtra (macOS-only)

Renders a persistent control in the system menu bar. Two styles available:

  • .menu (default) — standard dropdown menu
  • .window — popover panel with custom SwiftUI views

Menu-style (dropdown)

MenuBarExtra("My Utility", systemImage: "hammer") {
    Button("Action One") { /* ... */ }
    Button("Action Two") { /* ... */ }
    Divider()
    Button("Quit") { NSApplication.shared.terminate(nil) }
}

Window-style (popover panel)

MenuBarExtra("Status", systemImage: "chart.bar") {
    DashboardView()
        .frame(width: 240)
}
.menuBarExtraStyle(.window)

Variations:

  • Toggleable — pass isInserted: with an @AppStorage binding to let users show/hide the extra: MenuBarExtra("Status", systemImage: "chart.bar", isInserted: $showMenuBarExtra)
  • Menu-bar-only app — use MenuBarExtra as the sole scene + set LSUIElement = true in Info.plist to hide the Dock icon. The app auto-terminates if the user removes the extra from the menu bar.

WindowGroup (macOS behavior)

On macOS, WindowGroup supports:

  • Multiple window instances — users can open many windows from File > New Window
  • Tabbed interface — users can merge windows into tabs
  • Automatic Window menu — commands for window management appear automatically
@main
struct Mail: App {
    var body: some Scene {
        // Basic multi-window support
        WindowGroup {
            MailViewer()
        }

        // Data-presenting window opened programmatically
        WindowGroup("Message", for: Message.ID.self) { $messageID in
            MessageDetail(messageID: messageID)
        }
    }
}

// Open a specific window programmatically
struct NewMessageButton: View {
    var message: Message
    @Environment(\.openWindow) private var openWindow

    var body: some View {
        Button("Open Message") {
            openWindow(value: message.id)
        }
    }
}

Key difference from Window: WindowGroup keeps the app running even after all windows are closed. Window (as sole scene) quits the app when closed.


Window

A single, unique window scene. The system ensures only one instance exists.

@main
struct Mail: App {
    var body: some Scene {
        WindowGroup {
            MailViewer()
        }

        // Supplementary singleton window
        Window("Connection Doctor", id: "connection-doctor") {
            ConnectionDoctor()
        }
    }
}

// Open programmatically — brings to front if already open
struct OpenDoctorButton: View {
    @Environment(\.openWindow) private var openWindow

    var body: some View {
        Button("Connection Doctor") {
            openWindow(id: "connection-doctor")
        }
    }
}

Window as sole scene

If Window is the only scene, the app quits when the window closes:

@main
struct VideoCall: App {
    var body: some Scene {
        Window("VideoCall", id: "main") {
            CameraView()
        }
    }
}

Recommendation: In most cases, prefer WindowGroup for the primary scene. Use Window for supplementary singleton windows.


UtilityWindow (macOS-only)

A specialized floating window for tool palettes and inspector panels. Available since macOS 15.0.

Key behaviors:

  • Receives FocusedValues from the focused main scene (like menu bar commands)
  • Floats above main windows (default level: .floating)
  • Hides when the app is no longer active
  • Only becomes focused when explicitly needed (e.g., clicking the title bar)
  • Dismissible with the Escape key
  • Not minimizable by default
  • Automatically adds a show/hide item to the View menu
@main
struct PhotoBrowser: App {
    var body: some Scene {
        WindowGroup {
            PhotoGallery()
        }

        UtilityWindow("Photo Info", id: "photo-info") {
            PhotoInfoViewer()
        }
    }
}

struct PhotoInfoViewer: View {
    // Automatically updates based on whichever main window is focused
    @FocusedValue(PhotoSelection.self) private var selectedPhotos

    var body: some View {
        if let photos = selectedPhotos {
            Text("\(photos.count) photos selected")
        } else {
            Text("No selection")
                .foregroundStyle(.secondary)
        }
    }
}

Tip: Remove the automatic View menu item with .commandsRemoved() and place a WindowVisibilityToggle elsewhere in your commands.


DocumentGroup

Document-based apps with automatic file management. On macOS, provides:

  • Document-based menu bar commands (File > New, Open, Save, Revert)
  • Multiple document windows simultaneously
  • On iOS, shows a document browser instead

SDK 27+: on iOS 27 / macOS 27 / visionOS 27 and later, prefer the Document protocol (ReadableDocument / WritableDocument) with the closure-based DocumentGroup initializer — see references/document-apps.md. The rest of this section covers FileDocument and ReferenceFileDocument, which are soft-deprecated in the SDK 27 toolchain but remain the compatible option for older deployment targets.

DocumentGroup(newDocument: TextFile()) { config in
    ContentView(document: config.$document)
}

For deployment targets below the 27 releases, the document type must conform to FileDocument (value type) or ReferenceFileDocument (reference type). Key requirements:

struct TextFile: FileDocument {
    static var readableContentTypes: [UTType] { [.plainText] }
    var text: String = ""
    init() {}
    init(configuration: ReadConfiguration) throws {
        text = String(data: configuration.file.regularFileContents ?? Data(), encoding: .utf8) ?? ""
    }
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        FileWrapper(regularFileWithContents: Data(text.utf8))
    }
}

For multiple document types, add additional DocumentGroup scenes — use DocumentGroup(viewing:) for read-only formats.


Platform Conditionals

Always wrap macOS-only scenes in #if os(macOS):

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }

        #if os(macOS)
        Settings {
            SettingsView()
        }

        MenuBarExtra("Status", systemImage: "bolt") {
            StatusMenu()
        }
        #endif
    }
}

Best Practices

  • Use Settings for preferences — prefer this over a custom preferences window
  • Use MenuBarExtra for menu bar items — prefer this over managing AppKit's NSStatusItem directly
  • Use WindowGroup as the primary scene — reserve Window for supplementary singletons
  • Use UtilityWindow for inspectors/palettes — it handles floating, focus, and visibility automatically
  • Use DocumentGroup for document-based apps — it provides the full File menu and document lifecycle
  • Gate macOS-only scenes with #if os(macOS) for multiplatform projects
  • Use openWindow(id:) to open windows programmatically — it brings existing windows to front

Source: SKILL.md on GitHub

No alerts2d5 checks · Risk SAFE
  • Gen Agent Trust Hub2d

    The skill is a professional-grade assistant for SwiftUI development and performance profiling. It includes Python scripts to interface with the Xcode xctrace CLI for recording and analyzing Instruments traces. All identified code and instructions are consistent with its stated purpose and follow security best practices.

  • Socket2d

    No alerts

  • Snyk2d

    Risk: LOW · No issues

  • Runlayer6mo

    19 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1e522cf. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 days ago
  • Performance
  • swiftui
  • ios
  • macos
  • instruments
  • state-management
  • view-composition
  • accessibility
  • animations

README badge

README badge for avdlee/swiftui-agent-skill/swiftui-expert-skill

Provides guidance for writing, reviewing, and refactoring SwiftUI code for iOS and macOS, including state management, view composition, performance optimization, and Instruments trace recording and analysis. Covers deprecated API detection, animation patterns, accessibility, and Liquid Glass adoption.

Generated from the current SKILL.md.

Does this skill work with both iOS and macOS?
Yes. The skill covers SwiftUI for both iOS and macOS, with dedicated reference sections for macOS-specific patterns like scenes, window styling, and views (HSplitView, Table, PasteButton).
Can this skill help me record and analyze Instruments traces?
Yes. The skill includes workflows to record traces via `record_trace.py` (with template selection for real devices vs simulators) and analyze them via `analyze_trace.py` to identify hangs, hitches, CPU hotspots, and excessive view updates.
Does this skill enforce a specific architecture pattern?
No. It focuses on correctness and performance without mandating MVVM, VIPER, or other architectural styles, though it encourages separating business logic from views for testability.
What does the skill do about deprecated APIs?
It consults `references/latest-apis.md` at the start of every task to identify and replace deprecated APIs with modern equivalents across iOS 15+ through iOS 26+, and gates version-specific APIs with `#available`.
Does this skill handle Liquid Glass effects?
Yes, but only when explicitly requested by the user. It includes guidance in `references/liquid-glass.md` for iOS 26+ Liquid Glass adoption with sensible fallbacks for earlier versions.

Generated from the current SKILL.md. These answers refresh after source changes.