Spatial SwiftUI: SpatialContainer
A Layout that can align overlapping views, allowing multiple views to exist in one space.
Overview
visionOS 26 brings a new type of Layout: SpatialContainer. This lets multiple views exist in the same space. The container will be shaped like a bounding box, sized to fit the largest child on each axis. We can align the content with an Alignment3D value.
Let’s create a SwiftUI box and place a 3D model inside, then align them.
SpatialContainer(alignment: .top) {
// A helper function to create a SwiftUI box using ZStacks and colors.
debugBorder3DView(showDebugLines ? .white : .clear)
.frame(width: 200, height: 200)
.frame(depth: 200)
ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
.frame(width: 100, height: 100)
}We can do something similar with multiple 3D models. We’ll adjust the opacity of the larger view so we can see the small one inside.
SpatialContainer(alignment: .top) {
ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
.opacity(0.22)
.frame(width: 200, height: 200)
ModelViewSimple(name: "Moon", bundle: realityKitContentBundle)
.frame(width: 100, height: 100)
}We already learned about spatialOverlay. That modifier uses SpatialContainer when we pass it more than one view. From the docs:
Multiple views provided by content are organized into aÂ
SpatialContainer.
Of course, we could pass spatialOverlay our own `SpatialContainer if we need to define alignment.
I find it helpful to think of this as a 3D Stack. The SwiftUI stacks that we use let us lay out views along an axis in a rectangle. SpatialContainer lets us lay out views in a 3D bounding box.
One powerful use case that comes to mind is transitioning from a Model3D to a RealityView. We size both views to fill the same space. We’ll look at an example of that in a future lab.
Video Demo
Example Code
struct Example094: View {
@State private var alignment: Alignment3D = .center
@State private var showDebugLines = true
var body: some View {
HStackLayout().depthAlignment(.center) {
// A container with a SwiftUI box and a 3D model
SpatialContainer(alignment: alignment) {
debugBorder3DView(showDebugLines ? .white : .clear)
.frame(width: 200, height: 200)
.frame(depth: 200)
ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
.frame(width: 100, height: 100)
.debugBorder3D(showDebugLines ? .blue : .clear)
}
// A container with two 3D models
SpatialContainer(alignment: alignment) {
ModelViewSimple(name: "Earth", bundle: realityKitContentBundle)
.opacity(0.22)
.frame(width: 200, height: 200)
.debugBorder3D(showDebugLines ? .blue : .clear)
ModelViewSimple(name: "Moon", bundle: realityKitContentBundle)
.frame(width: 100, height: 100)
.debugBorder3D(showDebugLines ? .green : .clear)
}
}
// Controls to modify the example
.ornament(attachmentAnchor: .scene(.trailing), contentAlignment: .trailing, ornament: {
VStack(alignment: .center, spacing: 8) {
Button(action: {
withAnimation {
alignment = .center
}
}, label: {
Text("Demo 1")
})
Button(action: {
withAnimation {
alignment = .top
}
}, label: {
Text("Demo 2")
})
Button(action: {
withAnimation {
alignment = .bottomLeadingFront
}
}, label: {
Text("Demo 3")
})
Button(action: {
showDebugLines.toggle()
}, label: {
Text("Debug")
})
}
.padding()
.controlSize(.small)
.glassBackgroundEffect()
})
}
}Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision