- Aug 1, 2025
Customize Toolbar Layouts with ToolbarSpacer in iOS 26
- DevTechie Inc
With the release of iOS 26, Apple introduced numerous new APIs for SwiftUI, including the ToolbarSpacer. This versatile view serves as a space item that creates deliberate visual breaks in the toolbar between items, effectively pushing them apart. By using spacers, developers can achieve a desired layout and balance within their apps.
To illustrate this concept, let’s consider an example. We will start with a simple LinearGradient view for our background.
struct LinearGradientView: View {
let startColor: Color
let endColor: Color
var body: some View {
LinearGradient(gradient: Gradient(colors: [startColor, endColor]), startPoint: .topLeading, endPoint: .bottomTrailing)
.opacity(0.9)
.ignoresSafeArea()
}
}Next, we’ll create a ContentView that contains a NavigationStack. Inside the NavigationStack, we’ll create a VStack and a Text view.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {We intend to use LinearGradientView as the background for this VStack. Therefore, we will set the maxWidth and maxHeight for the VStack to infinity, allowing it to occupy as much space as possible.
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)We are ready to add LinearGradientView a the background for VStack
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)Next, we’ll add the toolbar modifier to the VStack. The toolbar modifier expects a collection of toolbar items which we can be provided either by supplying a collection of views with each view wrapped in a ToolbarItem, or by providing a collection of views as a ToolbarItemGroup.
ToolbarItemGroup allows us to group ToolbarItems, which can then be placed in the toolbar or navigation bar.
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {Toolbar’s primary action is a frequently used action for the current context. For instance, a button the user taps to compose a new message in a chat app.
On macOS and Mac Catalyst apps, the primary action is located at the leading edge of the toolbar. In iOS, iPadOS, and tvOS, the primary action is situated at the trailing edge of the navigation bar.
For the first group, we will show two button so let’s create computed properties for buttons.
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}We will use these buttons directly inside the ToolbarItemGroup.
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
favoriteButton
bookmarkButton
}Now is the time to use newly introduced ToolbarSpacer. This spacer will create visual break between ToolbarItemGroups in liquid glass design.
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
favoriteButton
bookmarkButton
}
ToolbarSpacer(.flexible, placement: .primaryAction)Just like Spacer view in SwiftUI, the ToolbarSpacer doesn’t take effect until we’ve placed it between two views. So, we’ll do just that. We’ll also create another computed property for the settings button to be displayed in the Toolbar.
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}
@ViewBuilder
var settingsButton: some View {
Button {
} label: {
Image(systemName: "gear")
}
}Let’s add another ToolbarItemGroup and add settingsButton to the view right after the ToolbarSpacer.
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}
@ViewBuilder
var settingsButton: some View {
Button {
} label: {
Image(systemName: "gear")
}
}
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
favoriteButton
bookmarkButton
}
ToolbarSpacer(.flexible, placement: .primaryAction)
ToolbarItemGroup(placement: .primaryAction) {
settingsButton
}
}
.navigationTitle("DevTechie.com")
}
}
}Complete code
import SwiftUI
struct ContentView: View {
@ViewBuilder
var favoriteButton: some View {
Button {
} label: {
Image(systemName: "heart")
}
}
@ViewBuilder
var bookmarkButton: some View {
Button {
} label: {
Image(systemName: "bookmark")
}
}
@ViewBuilder
var settingsButton: some View {
Button {
} label: {
Image(systemName: "gear")
}
}
var body: some View {
NavigationStack {
VStack {
Text("Learn iOS development with DevTechie.com")
.font(.largeTitle)
}
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
LinearGradientView(startColor: .blue, endColor: .purple)
)
.toolbar {
ToolbarItemGroup(placement: .primaryAction) {
favoriteButton
bookmarkButton
}
ToolbarSpacer(.flexible, placement: .primaryAction)
ToolbarItemGroup(placement: .primaryAction) {
settingsButton
}
}
.navigationTitle("DevTechie.com")
}
}
}
#Preview {
ContentView()
}
struct LinearGradientView: View {
let startColor: Color
let endColor: Color
var body: some View {
LinearGradient(gradient: Gradient(colors: [startColor, endColor]), startPoint: .topLeading, endPoint: .bottomTrailing)
.opacity(0.9)
.ignoresSafeArea()
}
}
