Skip to content

Toggle

A toggle is a switch for a setting that takes effect at once, such as Wi-Fi or a dark theme. Flipping it is the action itself; there is no “apply” button after it. Use it in settings lists and forms where every change should apply immediately.

The switch draws a track and a knob and nothing else. It has no text of its own: you put the label next to it, usually in a row or an HStack.

Toggle Toggle
wifi := ctx.State("wifi", true)
bluetooth := ctx.State("bluetooth", false)
airplane := ctx.State("airplane", true)

row := func(title string, toggle ui.ToggleView) gift.View {
	return ui.HStack(ui.Text(title), ui.Spacer(), toggle.Label(title)).
		MinWidth(300).
		Align(geom.Alignment{X: 0, Y: 0.5})
}

return ui.Card(
	row("Wi-Fi", ui.Toggle(ctx.Read(wifi), wifi.Set)),
	row("Bluetooth", ui.Toggle(ctx.Read(bluetooth), bluetooth.Set)),
	row("Airplane mode", ui.Toggle(ctx.Read(airplane), airplane.Set).Tint(ui.ColorDanger)),
	row("Location (managed)", ui.Toggle(true, nil).Disabled(true)),
	row("Roaming (managed)", ui.Toggle(false, nil).Disabled(true)),
).Gap(4)

Full demo on GitHub ↗ · run it with go run ./docs/gallery -demo toggle

Usage

State flows in and out

ui.Toggle(on, onChange) draws the value on and calls onChange with the value the user asked for. The switch keeps no state of its own. Nothing moves until you store the new value and the view rebuilds:

dark := ctx.State("dark", false)
ui.Toggle(ctx.Read(dark), func(on bool) { dark.Set(on) }).Label("Dark mode")

Because State.Set already has the shape func(bool), ui.Toggle(ctx.Read(dark), dark.Set) works as well.

Read the value with ctx.Read, not with dark.Get(). Get registers no dependency, so Set does not rebuild the view and the switch does not move until something else rebuilds it. See State.

Since the application decides, a switch can also refuse a change. If onChange does not store the value, the switch stays where it is:

locked := ctx.State("locked", true)
ui.Toggle(ctx.Read(locked), func(on bool) {
	if !isAdmin {
		return // nothing is stored, so the switch stays where it is
	}
	locked.Set(on)
}).Label("Kiosk lock")

The knob slides over ui.ControlAnimation (180 ms) whenever the value changes, no matter who changed it: a tap, a key, or your code setting the state from a timer.

Operating it

Tap the switch, or focus it and press space or enter. A press captures the pointer like a button: a finger that slides off before it lifts changes nothing. The knob cannot be dragged from one side to the other; a tap does the job.

Label

Label sets the accessible name of the switch, the name a person would give the setting. It is never drawn. Set it anyway: the switch has no text, so without it nothing in the view tree says which setting it controls.

Disabled and inert

Disabled(true) takes the switch out of the focus order and out of input. The off track turns to ui.ColorControlDisabled, and an on switch keeps its tint at a third of its strength, so the user can still see which way it points.

A nil onChange makes a switch inert but leaves it focusable and looking active. Prefer Disabled for a setting that is unavailable, because that is the state the user can see.

In a list row

A switch is the typical accessory of a row. Tapping the switch flips it without also running the row’s OnTap. RowView.Disabled does not disable the accessory, so disable both:

ui.List(
	ui.Row("Notifications").
		Accessory(ui.Toggle(ctx.Read(notify), notify.Set).Label("Notifications").Disabled(managed)).
		Disabled(managed),
)

Color and size

Tint replaces the accent color of the on track, for example with ui.ColorDanger. It accepts a semantic color. The off track and the knob cannot be changed per switch. They use the ui.ColorControl and ui.ColorSurface roles of the theme, so they follow the theme like every other control.

The drawn switch always has the same size, 51 by 31 logical pixels. Its hit area asks for at least ui.ControlHitTarget (44 pixels) on both axes, so the space just above and below the track also reacts to a finger. A smaller Frame or a tight constraint from the parent wins, down to the size of the track; only below that does the toggle report an overflow. Frame, MinWidth and MinHeight make the hit area larger; the track stays the same size and stays centered.

API

Constructors

ConstructorDescription
func Toggle(on bool, onChange func(bool)) ToggleViewToggle returns a switch showing on and calling onChange with the value the user asked for.

Methods

MethodDescription
Disabled(v bool) ToggleViewDisabled takes the switch out of input.
Label(v string) ToggleViewLabel sets the accessible name of the switch: what a person would call the setting.
Tint(v Color) ToggleViewTint sets the colour of the track while the switch is on, replacing ColorAccent.

Common modifiers: Flex, Frame, Key, MinHeight, MinWidth. See Modifiers.

ui.ToggleView on pkg.go.dev ↗

Related