Forms and input

SwiftUI forms: Toggle

Learn how to use the Toggle control in SwiftUI to get an on or off choice from the user, binding a Bool value to its isOn parameter like the Settings app.

Toggle gets an on/off choice from the user. It’s the switch you see on almost every row of the Settings app.

A Toggle needs a Bool to read and write. We store it in a @State property and pass it with the $ prefix:

struct ContentView: View {
    @State private var enabled = true
    
    var body: some View {
        Form {
            Toggle("Enable?", isOn: $enabled)
        }
    }
}

Xcode showing SwiftUI Toggle code with iPhone simulator displaying a green enabled toggle control

It works like the TextField we saw in the last lesson. The difference is the type: instead of a String passed to text, we pass a Bool to isOn.

The initial value decides how the switch starts. With true it starts on. Change it to false and it starts off:

Xcode showing SwiftUI Toggle code with iPhone simulator displaying a gray disabled toggle control

When the user flips the switch, the bound property updates. When your code changes the property, the switch flips. The binding works in both directions.

Using the value elsewhere

The whole point of binding state is that the rest of the view can react to it. Here’s a realistic notifications setting:

struct SettingsView: View {
    @State private var notificationsEnabled = false
    @State private var playSounds = true

    var body: some View {
        Form {
            Toggle("Allow notifications", isOn: $notificationsEnabled)

            if notificationsEnabled {
                Toggle("Play sounds", isOn: $playSounds)
            }
        }
    }
}

The “Play sounds” row only exists while notifications are on. Flip the first toggle and watch the second row slide in and out. Inside a Form or a List, SwiftUI animates the insertion for you. Outside those containers, ask for it with .animation(.default, value: notificationsEnabled) on the enclosing stack.

We looked at this pattern in more depth in the conditional views lesson.

Labels with an icon

The label doesn’t have to be plain text. Pass a Label to get an icon next to it, like the rows in the Settings app:

Toggle(isOn: $notificationsEnabled) {
    Label("Notifications", systemImage: "bell.badge")
}

Toggle styles

On iOS the default look is the switch. You can change it with the toggleStyle() modifier.

.button turns the toggle into a button that shows a highlighted state when on:

Toggle("Bold", isOn: $isBold)
    .toggleStyle(.button)

This is great for toolbars and formatting controls, where a switch would look out of place. Think of the B button in a text editor.

On macOS the default inside a form is a checkbox. If you want the iOS-style switch there too, ask for it with .toggleStyle(.switch).

Lesson completed