4.3k

Pagination

A row container for page navigation — children flow horizontally and are ordinary buttons: ghost page numbers with the current page carrying the outline variant and selected, chevron-left/chevron-right buttons for previous/next (icon-placement="trailing" puts the next chevron after its label), and an ellipsis icon standing in for a collapsed range. Each button dispatches its own Msg through on-press; the model owns the current page.

pagination
A pagination row rendered by the engine (light theme)
previous/next chevrons around ghost page buttons, page 1 selected

Markup

<pagination>
  <button variant="ghost" icon="chevron-left" on-press="prev_page">Previous</button>
  <for each="pages" as="p" key="number">
    <button variant="{p.variant}" selected="{p.number == page}" on-press="open_page:{p.number}">{p.label}</button>
  </for>
  <icon name="ellipsis" />
  <button variant="ghost" icon="chevron-right" icon-placement="trailing" on-press="next_page">Next</button>
</pagination>

The current page is the outline one among ghost siblings — the variant carries the currency, selected carries the semantics. In a for loop, compute the variant name on the row (p.variant returning outline or ghost).

Zig builder

ui.el(.pagination, .{}, .{
    ui.button(.{ .variant = .ghost, .icon = "chevron-left", .on_press = .prev_page }, "Previous"),
    ui.button(.{ .variant = .outline, .selected = model.page == 1, .on_press = .{ .open_page = 1 } }, "1"),
    ui.button(.{ .variant = .ghost, .on_press = .{ .open_page = 2 } }, "2"),
    ui.button(.{ .variant = .ghost, .on_press = .{ .open_page = 3 } }, "3"),
    ui.icon(.{}, "ellipsis"),
    ui.button(.{ .variant = .ghost, .icon = "chevron-right", .icon_placement = .trailing, .on_press = .next_page }, "Next"),
})

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).
iconbutton, 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-placementIcon 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.