How to Open a Grid of Windows in visionOS
We can open windows placed relative to existing windows, creating custom grid formations.
Overview
Let’s build on the Synced Window Sets example. Imagine we want to create a grid of secondary windows around the main window.

We can use defaultWindowPlacement to open four of these relative to the main window. We have an easy answer for top, bottom, leading, and trailing.
// Example of the Top Window
WindowGroup(id: "TopCenter") {
Text("↖️")
.font(.system(size: 128))
.persistentSystemOverlays(.hidden)
}
.defaultSize(CGSize(width: 300, height: 300))
.defaultWindowPlacement { _, context in
if let mainWindow = context.windows.first(where: { $0.id == "MainWindow" }) {
return WindowPlacement(.above(mainWindow))
}
return WindowPlacement(.none)
}So how about those two windows in the top corners? visionOS doesn’t have a .topLeading or.topTrailing placement so we need to get creative.
In this example, we’ll use the new top window to place the top leading and trailing windows.
// Top Leading (leading of TopCenter)
WindowGroup(id: "TopLeading") {
Text("↖️")
.font(.system(size: 128))
.persistentSystemOverlays(.hidden)
}
.defaultSize(CGSize(width: 300, height: 300))
.defaultWindowPlacement { _, context in
if let topWindow = context.windows.first(where: { $0.id == "TopCenter" }) {
return WindowPlacement(.leading(topWindow))
}
return WindowPlacement(.none)
}
// Top Trailing (trailing of TopCenter)
WindowGroup(id: "TopTrailing") {
Text("↗️")
.font(.system(size: 128))
.persistentSystemOverlays(.hidden)
}
.defaultSize(CGSize(width: 300, height: 300))
.defaultWindowPlacement { _, context in
if let topWindow = context.windows.first(where: { $0.id == "TopCenter" }) {
return WindowPlacement(.trailing(topWindow))
}
return WindowPlacement(.none)
}We need to make sure the top window is open first, so we’ll loop over an array, opening these secondary windows from top to bottom, waiting a short time between openWindow calls.
This doesn’t guarantee the windows are open. In a production app, we may want to have each window report its open status before proceeding. We could to that by using Scene Phase to write to a central store that all windows can share.
let windowSequence: [[String]] = [
["BottomCenter"],
["MiddleLeading", "MiddleTrailing"],
["TopCenter"],
["TopLeading", "TopTrailing"],
]
Task {
for group in windowSequence {
for id in group {
openWindow(id: id)
}
try? await Task.sleep(for: .milliseconds(150))
}
}Video Demo
See it in action. Whenever we open the secondary windows, we create this grid from top to bottom. The uses can move the main window at any time. Our window grid will close and reopen relative to the new position of the main window.
Video demo of a grid formation of windows placed around a main window
Hopefully visionOS 27 will bring better support for groups or sets of windows, but for now we can use techniques like this.
Sample code for this post is available in Garden035 in Step Into Examples on GitHub
Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision