The macOS 13 and iOS 16 scene APIs make windows declarative: a Window scene for singletons, value-typed WindowGroups for per-item windows, openWindow to open them, and MenuBarExtra for menu bar apps.
Check Support, Then Open by Id
\.supportsMultipleWindows tells you whether the platform can open extra windows. The Window scene declares one unique window with an id, and \.openWindow opens it.
@main struct MyApp: App {
var body: some Scene {
#if os(macOS)
Window("Statistics", id: "stats") {
StatisticsView()
}
#endif
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@Environment(\.openWindow) private var openWindow
var body: some View {
Button("Open statistics") {
openWindow(id: "stats")
}
}
}
Value-Typed Window Groups
WindowGroup(for:) registers a group keyed by a value type. Opening a window with a value routes it to that group, one window per item.
WindowGroup(for: Item.ID.self) { $itemId in
ItemView(itemId: itemId ?? UUID())
}
WindowGroup(id: "editor") {
EditorView()
}
// call sites
openWindow(id: "item", value: item.id)
openWindow(id: "editor")
The binding's value can be nil (a window restored without its value), so provide a fallback.
Styling
windowStyle on the scene toggles titleBar versus hiddenTitleBar. presentedWindowStyle on a view hierarchy styles the windows that hierarchy opens.
Menu Bar Apps With MenuBarExtra
MenuBarExtra is a scene that lives in the macOS menu bar. The isInserted binding shows or hides the icon, and menuBarExtraStyle(.window) renders the content in a floating window instead of a pull-down menu.
@main struct MyApp: App {
@State private var menuBarExtraShown = true
var body: some Scene {
#if os(macOS)
MenuBarExtra(isInserted: $menuBarExtraShown) {
MenuBarView()
} label: {
Label("MyApp", systemImage: "star")
}
.menuBarExtraStyle(.window)
#endif
WindowGroup {
ContentView()
}
}
}