Skip to content
Buttons and actions

Buttons and actions

Actions are what the user taps to make something happen. Bellui has one general Button and several specialised buttons for the MD3 patterns.

Which one to use

You wantUse
A labelled action, the default choiceButton
The single most important action on a screen, floating above contentFAB (NewFAB, NewExtendedFAB)
A floating button that opens several related actionsFABMenu
A compact action shown only as an iconIconButton
A choice between 2 to 5 mutually exclusive optionsSegmentedButton
A main action with alternatives in a drop-downSplitButton
Several related actions joined into one shapeButtonGroup
Small actions, filters or tags among contentChip
A row of icon actions along the top of a windowToolbar

Button

widget.NewButton takes a label and a function that runs when the button is tapped. NewButtonWithIcon adds a leading icon.

save := widget.NewButton("Save", func() {
	status.SetText("Saved")
})
open := widget.NewButtonWithIcon("Open", theme.FolderOpenIcon(), say("Open"))

Space activates a focused button, as a tap does. SetText and SetIcon change the button later and are safe to call from any goroutine. Pass nil to SetIcon to remove the icon.

Styles

The Style field picks one of the MD3 button variants:

filled := widget.NewButton("Filled", say("Filled"))
filled.Style = widget.ButtonStyleFilled
tonal := widget.NewButton("Tonal", say("Tonal"))
tonal.Style = widget.ButtonStyleFilledTonal
elevated := widget.NewButton("Elevated", say("Elevated"))
elevated.Style = widget.ButtonStyleElevated
outlined := widget.NewButton("Outlined", say("Outlined"))
outlined.Style = widget.ButtonStyleOutlined
text := widget.NewButton("Text", say("Text"))
text.Style = widget.ButtonStyleText
StyleLooks like
ButtonStyleFilledPrimary colour fill, the strongest emphasis
ButtonStyleFilledTonalSecondary container fill
ButtonStyleElevatedLow surface fill with primary-coloured text
ButtonStyleOutlinedA border and primary-coloured text
ButtonStyleTextPrimary-coloured text only, the lightest emphasis

Importance

When Style is left at ButtonStyleDefault, the Importance field chooses the colours instead:

  • HighImportance draws the button as ButtonStyleFilled.
  • MediumImportance (the default) and LowImportance draw it as ButtonStyleFilledTonal.
  • DangerImportance, WarningImportance and SuccessImportance fill it with the theme’s error, warning and success colours.

A Style other than the default wins over Importance.

del := widget.NewButtonWithIcon("Delete", theme.DeleteIcon(), say("Deleted"))
del.Importance = widget.DangerImportance

next := widget.NewButtonWithIcon("Next", theme.NavigateNextIcon(), say("Next"))
next.Importance = widget.HighImportance
next.IconPlacement = widget.ButtonIconTrailingText

Alignment moves the icon and text to the leading or trailing edge (ButtonAlignLeading, ButtonAlignTrailing), and IconPlacement puts the icon after the text with ButtonIconTrailingText.

Icon buttons

IconButton shows only an icon. Its Style is IconButtonStyleStandard (no background), IconButtonStyleFilled, IconButtonStyleFilledTonal or IconButtonStyleOutlined.

settings := widget.NewIconButton(theme.SettingsIcon(), say("Settings"))
settings.SetAccessibilityLabel("Settings")
settings.SetToolTipText("Settings")

add := widget.NewIconButton(theme.ContentAddIcon(), say("Add"))
add.Style = widget.IconButtonStyleFilled

An icon button has no text, so screen readers have nothing to announce. Give it a name with SetAccessibilityLabel, and a hover hint with SetToolTipText.

Button groups, segmented and split buttons

group := widget.NewButtonGroup(
	widget.NewButton("Cut", say("Cut")),
	widget.NewButton("Copy", say("Copy")),
	widget.NewButton("Paste", say("Paste")),
)

period := widget.NewSegmentedButton([]string{"Day", "Week", "Month"}, func(i int) {
	status.SetText(fmt.Sprintf("Segment %d", i))
})
period.Selected = 1

split := widget.NewSplitButton("Export", say("Export"), []*bellui.MenuItem{
	bellui.NewMenuItem("Export as PDF", say("PDF")),
	bellui.NewMenuItem("Export as CSV", say("CSV")),
})
  • ButtonGroup joins ordinary buttons into one connected shape. Each button keeps its own OnTapped.
  • SegmentedButton shows a row of labels and keeps exactly one selected. OnChanged receives the index of the new selection, and Selected holds it (index 0 after NewSegmentedButton; -1 selects nothing). When it has focus, the left and right arrow keys move the selection.
  • SplitButton has a main action and an arrow that opens a menu of bellui.MenuItem alternatives.

Floating action buttons

A FAB is the floating button for a screen’s main action. NewFAB makes an icon-only FAB. NewExtendedFAB adds a label. Style picks the colour: FABStylePrimary (the default), FABStyleSurface, FABStyleSecondary or FABStyleTertiary.

compose := widget.NewExtendedFAB("Compose", theme.MailComposeIcon(), func() {
	status.SetText("Compose")
})
compose.Style = widget.FABStyleTertiary

A FAB is an ordinary widget, so you place it with a layout like any other. To keep it in a corner, put it at the end of a box with a spacer before it.

FAB menu

FABMenu is the MD3 speed dial: a list of labelled mini FABs that opens over the content. It is not a widget you place in a layout. You open it with Show, Toggle or close it with Hide, giving the canvas and a position. The menu opens above and to the left of that position. Tapping an item closes the menu and calls its OnTapped.

menu := widget.NewFABMenu(theme.ContentAddIcon(), []*widget.FABMenuItem{
	{Label: "Photo", Icon: theme.MediaPhotoIcon(), OnTapped: func() { status.SetText("Photo") }},
	{Label: "Document", Icon: theme.DocumentIcon(), OnTapped: func() { status.SetText("Document") }},
})

var add *widget.FAB
add = widget.NewFAB(theme.ContentAddIcon(), func() {
	// The menu opens above and to the left of the point you pass:
	// here, the FAB's top-right corner in window coordinates.
	pos := bellui.CurrentApp().Driver().AbsolutePositionForObject(add)
	menu.Toggle(w.Canvas(), pos.AddXY(add.Size().Width, 0))
})

Chips

A Chip is a small rounded label. Its Style decides what it is for:

  • ChipStyleAssist (from NewChip): an action, with an optional leading Icon.
  • ChipStyleFilter (from NewFilterChip): a toggle. Each tap flips Selected, fills the chip with the secondary container colour while it is selected, and calls your function with the new state.
  • ChipStyleInput: a tag the user can remove. Set OnDeleted; a tap on the trailing close mark calls it, and a tap anywhere else calls OnTapped.
  • ChipStyleSuggestion: an outlined label, drawn the same way as an assist chip.

There is no constructor for input and suggestion chips, so build them as a struct literal.

directions := widget.NewChip("Directions", func() {
	status.SetText("Directions")
})
directions.Icon = theme.NavigateNextIcon()

running := widget.NewFilterChip("Running", func(on bool) {
	status.SetText(fmt.Sprint("Running: ", on))
})
running.Selected = true

tags := container.NewHBox()
tag := &widget.Chip{Text: "golang", Style: widget.ChipStyleInput}
tag.ExtendBaseWidget(tag)
tag.OnDeleted = func() {
	tags.Remove(tag)
}
tags.Add(tag)

Toolbar

Toolbar lays out a row of toolbar items:

  • NewToolbarAction(icon, func): an icon button. It has Disable, Enable and SetIcon.
  • NewTwoStateToolbarAction(offIcon, onIcon, func(on bool)): a toggle that swaps icons, such as play and pause. SetOn changes the state from code.
  • NewToolbarSeparator(): a thin divider between groups.
  • NewToolbarSpacer(): empty space that stretches, which pushes the items after it to the far end. Several spacers share the space equally.
undo := widget.NewToolbarAction(theme.ContentUndoIcon(), func() {
	status.SetText("Undo")
})
play := widget.NewTwoStateToolbarAction(theme.MediaPlayIcon(), theme.MediaPauseIcon(),
	func(on bool) {
		status.SetText(fmt.Sprint("Playing: ", on))
	})

bar := widget.NewToolbar(
	widget.NewToolbarAction(theme.DocumentCreateIcon(), func() { status.SetText("New") }),
	widget.NewToolbarAction(theme.DocumentSaveIcon(), func() { status.SetText("Save") }),
	widget.NewToolbarSeparator(),
	undo,
	play,
	widget.NewToolbarSpacer(),
	widget.NewToolbarAction(theme.HelpIcon(), func() { status.SetText("Help") }),
)
undo.Disable()

Append and Prepend add items after the toolbar is created.