• 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.

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()
    }
}