Spatial SwiftUI: Window Toolbars

SwiftUI Toolbars are presented as Ornaments at the bottom of a window.

Overview

Toolbars can be useful to surface common actions in an easy-to-use location. Add a toolbar modifier to your view. I normally add this to the root of my SwiftUI view.

.toolbar {
  ...
}

Then create a ToolbarItemGroup with a placement value of .bottomOrnament.

.toolbar {

    ToolbarItemGroup(placement: .bottomOrnament) {
        // toolbar content
    }

}

We can think of these as horizontal stacks that we can fill with controls. For example, this toolbar has three toggle buttons with spacers and a divider to guide the layout.

.toolbar {
    ToolbarItemGroup(placement: .bottomOrnament) {
        Toggle("Offset", isOn: $showOffset.animation())
            .toggleStyle(.button)

        Toggle("Rotation", isOn: $showRotation.animation())
            .toggleStyle(.button)

        Spacer()
        Divider()
        Spacer()

        Toggle("Glass", isOn: $showGlass.animation())
            .toggleStyle(.button)
    }
}

It’s important not to overcrowd your toolbar with too many controls. If you explore some of the native Apple apps you will see that they use toolbars in two main ways

  1. Controls that pertain to actions on a window or type of content. Apple Notes has a great example of this. This toolbar contains controls to undo/redo edits, format text, toggle checklists, add tables, import attachments, and enable pencil kit.
  2. Controls that modify a content filter or mode. The Photos app is a perfect example. It has a simple toolbar with three buttons to change the photos library view from Years, to Months, to All. Combined with the main tab bar for navigation, this toolbar acts as a secondary layer of navigation for the content. Notice that this toolbar only appears when the Library tab is active.

The toolbar for our example borrows a few concepts from previous posts in this series. We have toggle buttons to enable the offset, rotation, and window glass background.

Video Demo

Full Example Code

struct Example044: View {
    @State private var showOffset = false
    @State private var showRotation = false
    @State private var showGlass = true
    var body: some View {
        VStack(spacing: 24) {
            HStack(spacing: 24) {
                RoundedRectangle(cornerRadius: 12.0)
                    .foregroundStyle(.stepRed)
                    .offset(x: showOffset ? -20 : 0)
                    .offset(z: showOffset ? 40 : 1)
                    .rotation3DEffect(
                        Angle(degrees: showRotation ? 25 : 0),
                        axis: (x: 0, y: 1, z: 0)
                    )
                RoundedRectangle(cornerRadius: 12.0)
                    .foregroundStyle(.stepBlue)
                RoundedRectangle(cornerRadius: 12.0)
                    .foregroundStyle(.stepGreen)
                    .offset(x: showOffset ? 20 : 0)
                    .offset(z: showOffset ? 40 : 1)
                    .rotation3DEffect(
                        Angle(degrees: showRotation ? -25 : 0),
                        axis: (x: 0, y: 1, z: 0)
                    )
            }
            .frame(height: 260)
        }
        .frame(height: 400)
        .padding(12)
        .glassBackgroundEffect(displayMode: showGlass ? .always : .never)
        .persistentSystemOverlays(showGlass ? .visible : .hidden)

        // 1. Add a toolbar
        .toolbar {
            // 2. Create an item group with bottomOrnament placement
            ToolbarItemGroup(placement: .bottomOrnament) {
                Toggle("Offset", isOn: $showOffset.animation())
                    .toggleStyle(.button)

                Toggle("Rotation", isOn: $showRotation.animation())
                    .toggleStyle(.button)

                // Optional: use spaces and dividers to lay out your controls
                Spacer()
                Divider()
                Spacer()

                Toggle("Glass", isOn: $showGlass.animation())
                    .toggleStyle(.button)
            }
        }
    }
}

Support our work so we can continue to bring you new examples and articles.

Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Questions or feedback?