$npx -y skills add fayazara/macos-app-skills --skill settings-uiBuild a proper macOS settings/preferences window with liquid glass support for macOS 26 (Tahoe). Use this skill whenever the user asks to create a settings window, preferences UI, settings view, or preferences pane for a macOS app. Also trigger when the user mentions "liquid glas
| 1 | # macOS Settings UI with Liquid Glass |
| 2 | |
| 3 | This skill produces a native macOS settings window that follows Apple's macOS 26 design guidelines. The result is a sidebar + detail NavigationSplitView with liquid glass window chrome, back/forward toolbar navigation, grouped Form sections with transparent backgrounds, and proper scroll edge effects. |
| 4 | |
| 5 | ## Architecture Overview |
| 6 | |
| 7 | The settings UI is composed of 3 layers: |
| 8 | |
| 9 | 1. **Window Controller** (`SettingsWindowController.swift`) — An `NSWindowController` that creates the `NSWindow` programmatically with `.fullSizeContentView`. This is what gives the window rounded liquid glass corners. You cannot get this effect from a SwiftUI `Window` scene. |
| 10 | |
| 11 | 2. **Root View** (`SettingsView.swift`) — A `NavigationSplitView` with a sidebar list and detail pane. Includes back/forward navigation history in the toolbar, which also forces the creation of an `NSToolbar` (required for the liquid glass title bar treatment). |
| 12 | |
| 13 | 3. **Detail Panes** (one file per tab) — Each pane uses `Form { Section(...) { ... } }.formStyle(.grouped).scrollContentBackground(.hidden)`. |
| 14 | |
| 15 | ## Why NSWindowController Instead of SwiftUI Window Scene |
| 16 | |
| 17 | SwiftUI's declarative `Window` scene does not expose the `NSWindow` style mask. The `.fullSizeContentView` flag must be set at window creation time for macOS 26 to render the liquid glass chrome (rounded corners, translucent sidebar, blurred title bar). Trying to inject it later via `NSViewRepresentable` is unreliable because SwiftUI resets the window's configuration. |
| 18 | |
| 19 | The `NSWindowController` approach also lets you control the toolbar style, frame autosave, minimum size, and delegate lifecycle directly. |
| 20 | |
| 21 | ## Critical Modifiers |
| 22 | |
| 23 | Every detail pane MUST have these three modifiers on its `Form`: |
| 24 | |
| 25 | ```swift |
| 26 | .formStyle(.grouped) |
| 27 | .scrollContentBackground(.hidden) |
| 28 | .contentMargins(.top, 8, for: .scrollContent) |
| 29 | ``` |
| 30 | |
| 31 | - `.formStyle(.grouped)` — gives the native inset rounded-rect section appearance |
| 32 | - `.scrollContentBackground(.hidden)` — makes the form background transparent so the liquid glass window chrome shows through. Without this, you get an opaque white/dark background that breaks the glass effect. |
| 33 | - `.contentMargins(.top, 8)` — adds breathing room between the toolbar and the first section |
| 34 | |
| 35 | The sidebar List MUST have: |
| 36 | |
| 37 | ```swift |
| 38 | .listStyle(.sidebar) |
| 39 | .scrollEdgeEffectStyleSoftIfAvailable() // macOS 26 progressive blur at scroll edges |
| 40 | .navigationTitle("Settings") |
| 41 | ``` |
| 42 | |
| 43 | The NavigationSplitView MUST have: |
| 44 | |
| 45 | ```swift |
| 46 | NavigationSplitView(columnVisibility: .constant(.all)) // sidebar always visible |
| 47 | // ... |
| 48 | .navigationTitle("Settings") |
| 49 | .navigationSplitViewStyle(.balanced) |
| 50 | ``` |
| 51 | |
| 52 | ## Reference Implementation |
| 53 | |
| 54 | Read the reference files for complete, working code: |
| 55 | |
| 56 | - `references/SettingsWindowController.swift` — The window controller (copy as-is, adapt the activation policy calls to your app) |
| 57 | - `references/SettingsView.swift` — The root view with sidebar, detail routing, and navigation history |
| 58 | - `references/ExampleDetailPane.swift` — A template detail pane showing common control patterns (Toggle, Picker, Slider, LabeledContent) |
| 59 | |
| 60 | ## Step-by-Step: Adding Settings to a New App |
| 61 | |
| 62 | ### 1. Create the Tab Enum |
| 63 | |
| 64 | Define your settings categories. Each case needs a title and SF Symbol icon: |
| 65 | |
| 66 | ```swift |
| 67 | enum SettingsTab: String, CaseIterable, Identifiable { |
| 68 | case general |
| 69 | case appearance |
| 70 | case about |
| 71 | |
| 72 | var id: Self { self } |
| 73 | |
| 74 | var title: String { |
| 75 | switch self { |
| 76 | case .general: "General" |
| 77 | case .appearance: "Appearance" |
| 78 | case .about: "About" |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | var systemImage: String { |
| 83 | switch self { |
| 84 | case .general: "gearshape" |
| 85 | case .appearance: "paintbrush" |
| 86 | case .about: "info.circle" |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | ``` |
| 91 | |
| 92 | ### 2. Create the Window Controller |
| 93 | |
| 94 | Copy `references/SettingsWindowController.swift` into your project. Adapt: |
| 95 | - The initial `contentRect` size (default `700x540` is good for most apps) |
| 96 | - The `minSize` (default `620x460`) |
| 97 | - The activation policy calls (`AppActivationPolicy.enter()/leave()`) — if your app isn't a menu-bar-only app, remove these |
| 98 | |
| 99 | ### 3. Create the Root Settings View |
| 100 | |
| 101 | Copy `references/SettingsView.swift`. Adapt: |
| 102 | - The `SettingsTab` enum cases to m |