Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Reviews, improves, and writes SwiftUI code following state management, view composition, performance, and iOS 26+ Liquid Glass best practices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/macos-window-styling.md
1# macOS Window & Toolbar Styling Reference23> Window configuration, toolbar styles, sizing, positioning, and navigation patterns specific to macOS SwiftUI apps.45## Table of Contents67- [Quick Lookup Table](#quick-lookup-table)8- [Toolbar Styles](#toolbar-styles)9- [Window Style](#window-style)10- [Window Sizing](#window-sizing)11- [MenuBarExtra Style (macOS-only)](#menubarextra-style-macos-only)12- [Navigation Layout (macOS behavior)](#navigation-layout-macos-behavior)13- [Commands & Keyboard](#commands--keyboard)14- [Best Practices](#best-practices)1516---1718## Quick Lookup Table1920| API | Availability | macOS-Only? | Usage |21|-----|-------------|:-----------:|-------|22| `windowToolbarStyle(_:)` | macOS 11.0+ | Yes | Sets toolbar style: `.unified`, `.unifiedCompact`, `.expanded` |23| `windowStyle(_:)` | macOS 11.0+ | No | Supports `.hiddenTitleBar` for chromeless windows |24| `windowResizability(_:)` | macOS 13.0+ | No | Controls resize handle and green zoom button behavior |25| `defaultSize(width:height:)` | macOS 13.0+ | No | Initial frame size when user creates a new window |26| `defaultPosition(_:)` | macOS 13.0+ | No | Initial window position on screen |27| `windowIdealPlacement(_:)` | macOS 15.0+ | No | Closure with display geometry for precise window positioning |28| `menuBarExtraStyle(_:)` | macOS 13.0+ | Yes | Sets MenuBarExtra to `.menu` or `.window` style |29| `NavigationSplitView` | macOS 13.0+ | No | Columns always visible side-by-side on macOS; translucent sidebar |30| `Inspector` | macOS 14.0+ | No | Trailing-edge sidebar panel; resizable by dragging |3132---3334## Toolbar Styles3536### windowToolbarStyle (macOS-only)3738Controls how the toolbar and title bar are displayed. Applied to a scene.3940```swift41@main42struct MyApp: App {43var body: some Scene {44WindowGroup {45ContentView()46}47// Title bar and toolbar in a single row48.windowToolbarStyle(.unified)49}50}51```5253**Available styles:**5455| Style | Description |56|-------|-------------|57| `.automatic` | System default |58| `.unified` | Title bar and toolbar in a single combined row |59| `.unifiedCompact` | Same as unified but with reduced vertical height |60| `.expanded` | Title bar displayed above the toolbar (more toolbar space) |6162```swift63// Unified compact — minimal chrome64.windowToolbarStyle(.unifiedCompact)6566// Expanded — title bar above toolbar67.windowToolbarStyle(.expanded)6869// Unified with title hidden70.windowToolbarStyle(.unified(showsTitle: false))71```7273### Toolbar content7475```swift76struct ContentView: View {77@State private var searchText = ""7879var body: some View {80NavigationSplitView {81SidebarView()82} detail: {83DetailView()84}85.toolbar {86ToolbarItem(placement: .automatic) {87Button(action: addItem) {88Label("Add", systemImage: "plus")89}90}91}92.searchable(text: $searchText, placement: .sidebar)93}94}95```9697---9899## Window Style100101### windowStyle102103Set the visual style of a window. Use `.hiddenTitleBar` for chromeless, immersive windows.104105```swift106// Standard title bar (default)107WindowGroup {108ContentView()109}110.windowStyle(.titleBar)111112// Hidden title bar — chromeless window113WindowGroup {114ContentView()115}116.windowStyle(.hiddenTitleBar)117```118119> **Use case:** `.hiddenTitleBar` is useful for media players, custom-chrome apps, or immersive experiences where the standard title bar is unwanted.120121---122123## Window Sizing124125### windowResizability, defaultSize, defaultPosition126127These modifiers work together to configure window sizing and placement:128129```swift130WindowGroup {131ContentView()132.frame(minWidth: 600, minHeight: 400)133}134.defaultSize(width: 900, height: 600)135.defaultPosition(.center)136.windowResizability(.contentMinSize)137```138139**`windowResizability` options:**140141| Value | Behavior |142|-------|----------|143| `.automatic` | System decides resize behavior |144| `.contentSize` | Fixed to content size; no user resize; zoom button disabled |145| `.contentMinSize` | Resizable with minimum based on content's `minWidth`/`minHeight` |146147**`defaultPosition` options:** `.center`, `.topLeading`, `.top`, `.topTrailing`, `.leading`, `.trailing`, `.bottomLeading`, `.bottom`, `.bottomTrailing`148149**Guidelines:**150- Set `minWidth`/`minHeight` via `.frame()` on content, enforce with `.contentMinSize`151- Use `.defaultSize()` for initial dimensions (larger than minimums)152- `defaultSize` also accepts `CGSize`153154### windowIdealPlacement (macOS 15.0+)155156For precise programmatic positioning, use a closure with display geometry:157158```swift159.windowIdealPlacement { context in160let screen = context.defaultDisplay.visibleArea161return WindowPlacement(x: screen.midX, y: screen.midY,162width: screen.width / 2, height: screen.height)163}164```165166---167168## MenuBarExtra Style (macOS-only)169170Choose between dropdown menu and popover panel for `MenuBarExtra`.171172```swift173// Dropdown menu (default)174MenuBarExtra("Status", systemImage: "chart.bar") {175Button("Action") { /* ... */ }176}177.menuBarExtraStyle(.menu)178179// Popover panel with custom SwiftUI content180MenuBarExtra("Status", systemImage: "chart.bar") {181DashboardView()182}183.menuBarExtraStyle(.window)184```185186---187188## Navigation Layout (macOS behavior)189190### NavigationSplitView191192On macOS, `NavigationSplitView` displays columns side-by-side (never overlaid). The sidebar gets a translucent material background. Columns support variable-width resizing by the user.193194```swift195NavigationSplitView {196List(items, selection: $selectedId) { item in197Text(item.name)198}199.navigationSplitViewColumnWidth(min: 180, ideal: 220, max: 300)200} detail: {201DetailView(id: selectedId)202}203.navigationSplitViewStyle(.balanced)204```205206Use the three-column variant (`sidebar` / `content` / `detail`) for master-detail-detail layouts. Customize column widths with `.navigationSplitViewColumnWidth(min:ideal:max:)`.207208### Inspector (macOS 14.0+)209210A trailing-edge panel for supplementary information. On macOS, it appears as a sidebar-style panel that can be resized by dragging its edge.211212```swift213struct ContentView: View {214@State private var showInspector = false215216var body: some View {217MainContent()218.inspector(isPresented: $showInspector) {219InspectorView()220.inspectorColumnWidth(min: 200, ideal: 250, max: 400)221}222.toolbar {223ToolbarItem {224Button {225showInspector.toggle()226} label: {227Label("Inspector", systemImage: "info.circle")228}229}230}231}232}233```234235---236237## Commands & Keyboard238239### Commands, CommandGroup, CommandMenu240241Define menu bar commands. On macOS, these populate the menu bar directly. On iOS, they create key commands.242243```swift244.commands {245CommandMenu("Tools") {246Button("Run Analysis") { /* ... */ }247.keyboardShortcut("r", modifiers: [.command, .shift])248}249CommandGroup(after: .newItem) {250Button("New From Template...") { /* ... */ }251}252}253```254255**`CommandGroup` placement options:** `.replacing(_:)` replaces a system group, `.before(_:)` / `.after(_:)` inserts adjacent to it. Common placements: `.newItem`, `.saveItem`, `.help`, `.toolbar`, `.sidebar`.256257### KeyboardShortcut258259On macOS, shortcuts are displayed alongside menu items and in button tooltips on hover.260261```swift262Button("Save") {263save()264}265.keyboardShortcut("s", modifiers: .command)266267Button("Delete") {268delete()269}270.keyboardShortcut(.delete, modifiers: .command)271```272273### openWindow274275Programmatically open a window. If the target window is already open, brings it to the front.276277```swift278struct ToolbarActions: View {279@Environment(\.openWindow) private var openWindow280281var body: some View {282Button("Connection Doctor") {283openWindow(id: "connection-doctor")284}285286Button("Show Message") {287openWindow(value: message.id) // Type-matched to WindowGroup288}289}290}291```292293---294295## Best Practices296297- **Use `.unified` or `.unifiedCompact`** for most apps — `.expanded` only when you need many toolbar items298- **Set min frame sizes on content** and use `.windowResizability(.contentMinSize)` to enforce them299- **Always provide `defaultSize`** so new windows start at a reasonable size300- **Use `NavigationSplitView`** for sidebar navigation — not `HSplitView`301- **Use `Inspector`** for supplementary panels — it integrates with the toolbar automatically302- **Define `Commands`** for all repeatable actions — users expect keyboard shortcuts on macOS303- **Use `#if os(macOS)`** to wrap macOS-only window configuration in multiplatform projects304