Guides
Custom widgets
The widgets without a look that every widget is built on, and widgets of your own.
Every widget is built on a base, the same widget without a look: the base handles the pointer, the keyboard and the focus, and tells assistive technology what it is, and leaves every color, size and shape to the elements it returns, which you style as any other. Build a design of your own on them, as headless component libraries do on the web.
| Base | What it does |
|---|---|
ButtonBase |
a row that takes the focus, and reports Clicked for the pointer, Enter and Space |
CheckboxBase, SwitchBase, ToggleBase |
a row that toggles a *bool |
RadioBase |
a row that selects its value into a *T |
SliderBase |
sets a *float64 from where the pointer is across its content box, inside its padding, and with the arrows, Home and End |
TabsBase |
the tab List, whose Tabs choose a *int, with the arrows moving the choice and the focus |
SegmentedBase |
a Track of Segments, a radio group choosing a *int |
CollapsibleBase |
a Trigger that shows and hides what Panel builds, growing and shrinking it with Progress, which goes from 0 closed to 1 open |
SelectBase |
a Trigger opening a Popup of Items choosing a *T, which the arrows highlight (Highlighted) and Enter chooses |
ComboboxBase |
an Input whose text filters the Items of a Popup below it, which the arrows highlight and Enter or a click chooses (Chosen) |
PopoverBase, DialogBase |
a panel below an anchor, or over a backdrop covering the window, that a click outside or Escape closes |
TextInputBase, TextAreaBase |
text inputs without padding, background, border or corners |
A segmented control on SegmentedBase, and a select on SelectBase:
t := c.Theme()
view := ui.SegmentedBase(c, &app.view, 3)
view.Track.Padding(3).Radius(999).Background(t.Surface).Children(func() {
for i, name := range []string{"Day", "Week", "Month"} {
seg := view.Segment(i).Padding(5, 14).Radius(999)
if i == app.view {
seg.Background(t.Background).Shadow(0, 1, 2, 0, ui.RGBA(0, 0, 0, 0.15))
}
seg.Children(func() { ui.Text(c, name) })
}
})
sel := ui.SelectBase(c, &app.size)
sel.Trigger.Gap(6).Padding(6, 10).Radius(8).Border(1, t.Border).Children(func() {
ui.Text(c, app.size)
ui.Icon(c, chevron)
})
sel.Popup(func(panel *ui.Element) {
panel.Margin(4, 0, 0, 0).Padding(4).Radius(10).Background(t.Background).Border(1, t.Border)
for _, size := range sizes {
item := sel.Item(size).Padding(6, 10).Radius(6)
if item.Highlighted() {
item.Background(t.Accent).TextColor(t.AccentText)
}
item.Children(func() { ui.Text(c, size) })
}
})Bases ring the element with the keyboard focus, as every element taking
the focus is; FocusRing(false) turns the ring off for a widget that draws
its own, with Painter.FocusRing while FocusVisible.
Widgets of your own
Build your own widgets from elements. An element keeps state of its own
from frame to frame with ui.Local:
// Spoiler hides text until clicked.
func Spoiler(c *ui.Context, text string) {
t := c.Theme()
box := ui.Box(c).Padding(2, 6).Radius(4).Focusable()
shown := ui.Local(box, "shown", func() bool { return false })
if box.Clicked() {
*shown = !*shown
}
if *shown {
box.Background(t.Surface)
} else {
box.Background(t.Text) // the color of the text, hiding it
}
box.Children(func() { ui.Text(c, text) })
}Give a widget a role and a name for assistive
technology, take the keys it needs with Shortcut on its element, or every
key as it comes with HandleInput, and
paint what elements do not with Draw.