How it works
ToolbarContent is the protocol you conform to when you want to define a reusable, self-contained group of toolbar items as its own type, rather than inlining them in a .toolbar closure. It plays the same role for toolbars that View plays for ordinary interface: a type that conforms to ToolbarContent declares a body built from toolbar primitives, which SwiftUI then composes into the bar. Reach for it when a toolbar grows beyond a couple of buttons, when you want to share the same set of controls across screens, or when you simply want to lift bar configuration out of a busy view body. In the example, MyToolbar is a standalone ToolbarContent type that the NavigationStack adopts by passing it to .toolbar.
Conform a type to ToolbarContent
Declaring
struct MyToolbar: ToolbarContentcreates a dedicated value whose sole job is to describe toolbar items. Unlike a View, this type does not draw a region of the screen; it contributes entries to a host's toolbar. Because it is an ordinary struct, it can hold stored properties, take initializer parameters, and be reused anywhere a toolbar is accepted.Provide a body of associated type ToolbarContent
The protocol requires a single computed property,
var body: some ToolbarContent. This mirrors View'sbodybut its return type is toolbar content rather than a view. Inside it you list the items the type provides; here thebodyreturns twoToolbarItemvalues that SwiftUI assembles into the finished bar.Populate the body with ToolbarItem
ToolbarItem is the building block you place inside a ToolbarContent body, each wrapping a single control. In
MyToolbar, oneToolbarItemholds aButton("Edit")and another holds aButtoncontaining anImage(systemName: "square.and.pencil"). The view builder that produces the control runs inside the item's trailing closure.Position items with the placement parameter
Each
ToolbarItem(placement:)tells SwiftUI where in the bar the control belongs, letting the same ToolbarContent type adapt to different platforms and bar regions. The example sends the Edit button to.navigationBarLeadingand the compose button to.primaryAction, so the system decides their concrete position within the navigation bar.Attach the type with the toolbar modifier
A ToolbarContent type is installed by passing it to a view's
.toolbarmodifier, which is where the symbol plugs into the rest of the interface. Here.toolbar { MyToolbar() }hangs the items off theNavigationStack, so they render in the navigation bar alongside the.navigationTitle("Mail").
placement: .primaryAction to placement: .navigationBarLeading and watch the compose button jump to the leading edge next to Edit, showing how a ToolbarContent type's layout is driven entirely by each item's placement.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 ToolbarContentDemo: View {
var body: some View {
NavigationStack {
Text("Inbox")
.padding()
.navigationTitle("Mail")
.toolbar {
MyToolbar()
}
}
}
}
struct MyToolbar: ToolbarContent {
var body: some ToolbarContent {
ToolbarItem(placement: .navigationBarLeading) {
Button("Edit") {}
}
ToolbarItem(placement: .primaryAction) {
Button(action: {}) {
Image(systemName: "square.and.pencil")
}
}
}
}