Spatial SwiftUI: Building volumetric pickers with attachments
Exploring a workaround to system SwiftUI pickers that use presentations in RealityView attachments.
Update: Starting in visionOS 26, we can now use presentations in volumes. This post below is here just for reference for version 1 and 2.
If we try to open a picker in an RealityView attachment we will run into this error:
Presentations are not currently supported in Volumetric contexts.
We saw an option for working around this limitation when presenting an alert or sheet. Now let’s do the same thing with a picker. We’ll use a date picker for this example.
Let’s start with the attachment. We’ll use the SwiftUI DatePicker with a style set to .graphical. We can use this to present the calendar that would normally show in the popover for the control. This entire attachment will show that calendar. When we select a value, we’ll close the picker.
Attachment(id: "PickerContent") {
DatePicker("Select a date", selection: $date, displayedComponents: .date)
.datePickerStyle(.graphical)
.padding()
.frame(width: 460, height: 500)
.glassBackgroundEffect()
.opacity(showPicker ? 1 : 0)
.onChange(of: date) {
showPicker = false
}
}We’ll use the same attachment and transform code from the previous example. Let’s see how it looks.
There is a lot we could do improve this. Better animations would be a good start. We might also abstract this into a view and pass in just the bindings to the data it needs.
Full Example Code
struct Example054: View {
@State private var showPicker: Bool = false
@State private var date = Date()
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
let transformMain = Transform(
scale: SIMD3<Float>(repeating: 1),
rotation: simd_quatf(angle: 0, axis: SIMD3<Float>(0, 1, 0)),
translation: SIMD3<Float>(0, 0, -0.1)
)
let transformMainAlertShowing = Transform(
scale: SIMD3<Float>(repeating: 1),
rotation: simd_quatf(angle: 0, axis: SIMD3<Float>(0, 1, 0)),
translation: SIMD3<Float>(0, 0, -0.12)
)
let transformAlert = Transform(
scale: SIMD3<Float>(repeating: 1),
rotation: simd_quatf(angle: 0, axis: SIMD3<Float>(0, 1, 0)),
translation: SIMD3<Float>(0, 0.4, -0.1)
)
var body: some View {
RealityView { content, attachments in
guard let scene = try? await Entity(named: "SwiftUIScienceLab", in: realityKitContentBundle) else { return }
content.add(scene)
scene.position.y = -0.4
if let panel = attachments.entity(for: "AttachmentContent") {
panel.move(to: transformMain, relativeTo: scene)
content.add(panel)
}
if let alert = attachments.entity(for: "PickerContent") {
alert.move(to: transformAlert, relativeTo: scene)
alert.isEnabled = showPicker
content.add(alert)
}
} update: { content, attachments in
if let panel = attachments.entity(for: "AttachmentContent") {
panel
.move(
to: showPicker ? transformMainAlertShowing : transformMain,
relativeTo: panel.parent,
duration: 0.25,
timingFunction: .easeOut
)
}
if let alert = attachments.entity(for: "PickerContent") {
alert.isEnabled = showPicker
}
} attachments: {
Attachment(id: "AttachmentContent") {
VStack() {
Text("Volumetric Date Picker")
.font(.extraLargeTitle2)
Text("Click the button to show a volumetric picker. We'll use another attachment to show the date picker with the `.graphical` style. We will also move this attachment back a bit on the z axis when the picker is shown.")
Button(dateFormatter.string(from: date), action: {
withAnimation {
showPicker.toggle()
}
})
Spacer()
}
.opacity(showPicker ? 0 : 1)
.padding()
.frame(width: 460, height: 500)
.glassBackgroundEffect()
}
Attachment(id: "PickerContent") {
DatePicker("Select a date", selection: $date, displayedComponents: .date)
.datePickerStyle(.graphical)
.padding()
.frame(width: 460, height: 500)
.glassBackgroundEffect()
.opacity(showPicker ? 1 : 0)
.onChange(of: date) {
showPicker = false
}
}
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Follow Step Into Vision