Segmented Control
A standalone exclusive-choice segment. Each segmented-control is one named, pressable item: bind selected from the model, dispatch on-press, and add a vector icon when the label benefits from one. Put several in a row for a compact choice control; use tabs when you also need the tab-strip container and conditional panel.

Markup
<row gap="6">
<segmented-control selected="{range == 'day'}" on-press="choose_day">Day</segmented-control>
<segmented-control selected="{range == 'week'}" icon="settings" on-press="choose_week">Week</segmented-control>
<segmented-control selected="{range == 'month'}" on-press="choose_month">Month</segmented-control>
</row>selected is model-owned. Pressing a segment sends its message; the next view rebuild reflects the new selection. The segment itself is a text-bearing control, so it needs visible content or a label accessible name.
Icons and sizes
The icon attribute uses the same closed vector-icon vocabulary as button. It is drawn as part of the segment's own hit target and follows the segment's state tint. size selects the shared control register; label supplies an accessible name when the visible content is absent.
<row gap="6">
<segmented-control size="sm" selected="{view == 'list'}" icon="file-text" label="List" on-press="show_list" />
<segmented-control size="sm" selected="{view == 'board'}" icon="settings" label="Board" on-press="show_board" />
</row>Programmatic construction (Zig)
In a Zig view, use the same retained widget kind directly with canvas.Ui:
ui.row(.{ .gap = 6 }, .{
ui.el(.segmented_control, .{ .text = "Day", .selected = model.range == .day, .on_press = .choose_day }, .{}),
ui.el(.segmented_control, .{ .text = "Week", .icon = "settings", .selected = model.range == .week, .on_press = .choose_week }, .{}),
ui.el(.segmented_control, .{ .text = "Month", .selected = model.range == .month, .on_press = .choose_month }, .{}),
})Attributes
| Attribute | Description |
|---|---|
text | Text value for text-bearing elements; a literal or one {binding}. |
selected | Selected state; often a {a == b} equality. |
disabled | Disables the control; true/false or a {binding}. |
size | Control size: default|sm|lg|icon. On text, also the typography rungs heading|display (themable token steps above title - a section heading, a hero stat); numeric sizes are not accepted - retheme the typography tokens instead. |
icon | button, toggle-button, list-item, menu-item: vector icon drawn inline (buttons/toggle-buttons before the label, list/menu items as a leading slot): a built-in name (comptime-validated against canvas.icons.known_icon_names, e.g. save, plus, refresh-cw), an app-registered app:<name>, or one {binding} resolving to such a name. Icon-only buttons when the content is empty — add a label. One hit target, one enabled/disabled tint. |
icon-placement | Icon slot side on label-bearing buttons/toggle-buttons: leading (default) draws the icon before the label, trailing after it — the next-page chevron. Icon-only buttons center the glyph regardless. |
label | Accessible name; when set it REPLACES the element's text as the announced name - screen readers and automation snapshots see the label, never the text it shadows. |
key | Sibling-scoped identity key; on for, names an item field. |
global-key | Parent-independent identity: ids survive reparenting between containers. |
on-press | Dispatch a Msg on press: tag or tag:{payload}. Legal on any element — a bound press handler makes it pressable, and presses on plain text/icons inside it fall through to it (dragging still selects text). |
on-hold | Press-and-hold Msg: a pointer held ~350 ms dispatches it and the release then presses nothing; a quick click dispatches on-press as usual. A right/ctrl-click with no context menu on the route dispatches it immediately. Like on-press, binding it makes any element pressable. |
