How it works
OpenImmersiveSpaceAction presents an immersive space on visionOS, transitioning your app from a bounded window into the surrounding environment. You don't construct it yourself; SwiftUI provides a ready-made instance through the environment, and you call it like a function to request that a scene declared with ImmersiveSpace become active. Reach for it whenever a control in your interface should take the wearer out of the shared space and into your own fully or mixed immersive content, such as a galaxy, a room, or a guided experience.
Read the action from the environment with @Environment(\.openImmersiveSpace)
The action is delivered as an environment value rather than created directly, so SwiftUI can wire it to the active scene phase and platform. Bind it to a property using the openImmersiveSpace key path, as in
@Environment(\.openImmersiveSpace) private var openImmersiveSpace, and that property becomes a callable handle to the action for the rest of the view.Call the action and identify the space with the id parameter
Invoke the value like a function, passing the identifier you assigned to the corresponding ImmersiveSpace scene so SwiftUI knows which one to present. Here
openImmersiveSpace(id: "Galaxy")requests the space registered under "Galaxy"; the action also offers overloads that accept a value to pass into a data-driven space.Await the call inside a Task because it's asynchronous
Opening an immersive space is an async operation, so the call must be awaited from an asynchronous context. The example wraps it in a
Task { let result = await openImmersiveSpace(id: "Galaxy") }launched from theButtonaction, which keeps the synchronous body responsive while the system performs the transition.Branch on the returned OpenImmersiveSpaceAction.Result
The call resolves to a Result value reporting how the request finished, so you can update state accordingly. The
switch resulthandles.openedwhen the space becomes active,.userCancelledwhen the wearer dismisses the request, and.errorwhen presentation fails, with@unknown defaultcovering future cases — each arm here assigns a message tostatus.Trigger it from a control, only one space at a time
Because the action is just a callable handle, it slots naturally into any control's action closure, such as the
Button("Open Immersive Space")shown here. Note that a single immersive space is open at a time, so calling the action while one is already presented has no effect — dismiss the current space first.
openImmersiveSpace(id: "Galaxy") to an id that no scene declares and watch the result fall through to .error, setting status to "Failed to open".Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct OpenImmersiveSpaceActionDemo: View {
@Environment(\.openImmersiveSpace) private var openImmersiveSpace
@State private var status = "Tap to enter immersion"
var body: some View {
VStack(spacing: 16) {
Image(systemName: "visionpro")
.font(.largeTitle)
Text(status)
.font(.headline)
Button("Open Immersive Space") {
Task {
let result = await openImmersiveSpace(id: "Galaxy")
switch result {
case .opened: status = "Immersive space opened"
case .userCancelled: status = "User cancelled"
case .error: status = "Failed to open"
@unknown default: status = "Unknown"
}
}
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}