An ornament floats controls outside a visionOS window so they never crowd its content. Some come
free from TabView and the Toolbar API; the ornament modifier builds fully custom ones.
System Ornaments for Free
A plain TabView renders its tab bar as a system ornament on visionOS with hover behavior built
in. You cannot customize that ornament, and you do not need to.
The Toolbar API places actions in an ornament through the bottomOrnament placement.
Text("Hello World")
.toolbar {
ToolbarItem(placement: .bottomOrnament) {
Button("New", systemImage: "pencil") { /* action */ }
}
ToolbarItem(placement: .bottomOrnament) {
Button("Save", systemImage: "square.and.arrow.down") { /* action */ }
}
}
One Placement Per Platform
bottomOrnament exists only on visionOS. In a cross-platform app, compute the placement behind a
compile-time check.
private var placement: ToolbarItemPlacement {
#if os(visionOS)
return .bottomOrnament
#else
return .primaryAction
#endif
}
Custom Ornaments
The ornament modifier controls position, visibility, and content. attachmentAnchor picks the
scene point to attach to, contentAlignment picks which point of the ornament meets that anchor,
and visibility shows or hides it. Give the content glassBackgroundEffect so it matches the
platform material.
Text("Hello World!")
.ornament(
visibility: .visible,
attachmentAnchor: .scene(.bottomTrailing),
contentAlignment: .bottom
) {
VStack {
Button("New", systemImage: "pencil") { /* action */ }
Button("Save", systemImage: "square.and.arrow.down") { /* action */ }
}
.labelStyle(.iconOnly)
.padding(.vertical)
.glassBackgroundEffect()
}