6.7k

Slider

A draggable value control. The model owns value as a 0..1 fraction and renders it back on every rebuild; on-change dispatches when the user moves the thumb (drag, keyboard step, or accessibility set-value). In markup, on-change resolves by the named Msg arm's shape: a bare tag naming a VALUE arm — f32, or a transpiled core's one-number float arm — dispatches the applied fraction as its payload (the seek-bar shape), while a bare tag naming a void arm stays the plain "something changed" signal. Either way, update echoes the delivered value back into the model field. Reconcile follows the scroll rule: a source-side move wins (a model-driven value — playback progress on a seek bar — renders every rebuild), a source replaying the same value keeps the user's drag, and a live drag is never yanked mid-gesture. For a display-only bar, use progress.

slider
Sliders rendered by the engine (light theme)
a bound slider and a disabled slider

Markup

<column gap="20" width="280">
  <slider value="{volume}" on-change="volume_changed" label="Volume" />
  <slider value="0.7" disabled="true" label="Balance" />
</column>

With a one-number float arm — { kind: "volume_changed"; fraction: number } in a TypeScript core, volume_changed: f32 in a Zig core — the arm receives the applied fraction directly (the examples/soundboard-ts seek bar is the live pattern):

// in update: the value event delivers the applied fraction
case "volume_changed":
  return { ...model, volume: msg.fraction };
// in update: the value event delivers the applied fraction
.volume_changed => |fraction| model.volume = fraction,

A void volume_changed arm keeps the older plain form; the Options.sync hook remains available to Zig apps that mirror runtime widget state wholesale.

Programmatic construction (Zig)

In a Zig view, the canvas.Ui builder constructs the same tree programmatically; on_value = Ui.valueMsg(.tag) is the value channel:

ui.column(.{ .gap = 20, .width = 280 }, .{
    ui.el(.slider, .{
        .value = model.volume,
        .on_value = Ui.valueMsg(.volume_changed),
    }, .{}),
    ui.el(.slider, .{ .value = 0.7, .disabled = true, .semantics = .{ .label = "Balance" } }, .{}),
})

Attributes

AttributeDescription
valueValue for slider/progress/text entry; a literal or one {binding}.
disabledDisables the control; true/false or a {binding}.
on-changeDispatch a Msg on change: tag or tag:{payload}. Hit-target elements only (slider, ...).