Liquid Glass restyles toolbars automatically: glassy background, grouped items, symbol-first
buttons. The toolbar and ToolbarItem API is unchanged; the new work is picking placements,
grouping with ToolbarSpacer, and bridging label styles for pre-iOS 26 targets.
Symbols first, and a bridge for older OSes
Liquid Glass renders toolbar items as symbols, so give every button both a title and a
systemImage. On platforms before iOS 26 you may still want text-only items. Write a custom
LabelStyle that switches on availability, and mark it obsolete so raising the deployment
target forces its removal.
struct ToolbarLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
if #available(iOS 26, *) {
Label(configuration)
} else {
Label(configuration).labelStyle(.titleOnly)
}
}
}
@available(iOS, introduced: 18, obsoleted: 26, message: "Remove this property in iOS 26")
extension LabelStyle where Self == ToolbarLabelStyle {
static var toolbar: Self { .init() }
}
Placement now carries styling
ToolbarItemPlacement decides look as well as position: confirmationAction gets the
glassProminent button style automatically. Prefer the placement API over manual styling;
tint and badge work on toolbar items but are for rare emphasis.
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel", systemImage: "xmark") { }
.labelStyle(.toolbar)
}
ToolbarItem(placement: .confirmationAction) {
Button("Done", systemImage: "checkmark") { }
.labelStyle(.toolbar)
.badge(3)
}
}
Group with ToolbarSpacer
ToolbarSpacer splits a toolbar into separate glass groups, with .fixed or .flexible
spacing, so secondary tools sit apart from the primary action.
struct ToolsToolbar: ToolbarContent {
var body: some ToolbarContent {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel", systemImage: "xmark") {}
}
ToolbarItemGroup(placement: .primaryAction) {
Button("Draw", systemImage: "pencil") {}
Button("Erase", systemImage: "eraser") {}
}
ToolbarSpacer(.flexible)
ToolbarItem(placement: .confirmationAction) {
Button("Save", systemImage: "checkmark") {}
}
}
}