4.3k

Tabs

A tab strip: ONE muted rounded container (the house tab-strip treatment) whose triggers sit inside it — the active trigger lifts to the surface with a hairline, inactive triggers stay muted on the container's wash. The children are buttons whose selected state marks the active tab — usually an equality against a model field — and whose on-press switches it. The segmented-control foundation is what the engine renders tab triggers with: both markup engines lower <button> children of <tabs> to segmented_control widgets (the builder uses segmented_control children directly), so the strip renders identically however it is authored. The panel itself is ordinary conditional content: an if per tab under the strip.

tabs
A tab strip rendered by the engine (light theme)
Account selected in a three-tab strip

Markup

<column gap="16">
  <tabs>
    <button selected="{tab == account}" on-press="show_account">Account</button>
    <button selected="{tab == password}" on-press="show_password">Password</button>
    <button selected="{tab == team}" on-press="show_team">Team</button>
  </tabs>
  <if test="{tab == account}">
    <text foreground="text_muted">Manage your account details.</text>
  </if>
</column>

Zig builder

In the builder the strip's children are segmented_control elements — the widget kind the engine's tab strips are built on (segmented controls are a documented markup exclusion, so markup composes the strip from buttons instead).

ui.el(.tabs, .{}, .{
    ui.el(.segmented_control, .{ .text = "Account", .selected = model.tab == .account, .on_press = .show_account }, .{}),
    ui.el(.segmented_control, .{ .text = "Password", .selected = model.tab == .password, .on_press = .show_password }, .{}),
    ui.el(.segmented_control, .{ .text = "Team", .selected = model.tab == .team, .on_press = .show_team }, .{}),
})

Attributes

AttributeDescription
selectedSelected state; often a {a == b} equality.
on-pressDispatch 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).