Open Document-like Windows Using SwiftUI WindowGroup

Why would you need to open document-like windows without using SwiftUI’s document architecture?

Suppose you’re planning to use SwiftUI to make a Mac git client app like SourceTree or Fork. The app should open a window for each open git repo. SwiftUI’s document architecture supports opening a window for each open document, but a git repo can’t use most of the document architecture. You’re not going to open a blank repo window by pressing Cmd-N, save a repo by pressing Cmd-S, or mark a git repo as being edited. How do you open windows for each repo without using SwiftUI’s document architecture?

Create a SwiftUI app project and use the WindowGroup scene type to open additional windows. You must set up the window group to support creating additional windows and write code to open the window.

Setting up the Window Group

The body for the App struct in a new SwiftUI project has the following code:

var body: some Scene {
  WindowGroup {
    ContentView()
  }
}

To support creating additional windows, add a for argument to the WindowGroup and supply a data type. The data type should be one of your app model’s structs or classes that holds the data to show in the window.

Add an argument to the closure (after the opening brace) so that each window shows a unique instance of the window group’s data type.

The following code creates a new window for each open folder in the app and sets the window’s title to the folder’s display name:

struct Folder: Hashable, Codable {
  var url: URL
  var displayName: String {
    url.path.components(separatedBy: "/").filter{ !$0.isEmpty }.last ?? ""
  }
}

WindowGroup(for: Folder.self) { $folder in
  ContentView()
    .navigationTitle(folder?.displayName ?? "Window")
}

In a real app you would have a @Binding property in the content view and pass the equivalent of $folder as an argument to the content view.

Opening the Window

SwiftUI provides an openWindow environment property for opening windows in SwiftUI Mac apps. Add an @Environment property to your SwiftUI view.

@Environment(\.openWindow) private var openWindow

Create a new instance of the data structure you used as the for argument to the window group and pass that instance as the value to the openWindow function. The following code opens a new window for a user-selected folder:

// Get the URL from a file importer.
let folder = Folder(url: url)
openWindow(value: folder)

Add an Open menu item to the File menu or add a toolbar button to open new windows in your app.

Sample Project

I have a sample project on GitHub for you to view and download. Choose File > Open and select a folder on your Mac. The app creates a window and sets its title to the name of the selected folder.

Get the Swift Dev Journal Newsletter

Subscribe and get exclusive articles, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

    We won't send you spam. Unsubscribe at any time.