A styled range slider, in single-thumb and dual-thumb (range) forms.
Built on native <input type="range">. That is the whole accessibility
story: the browser gives us role="slider", aria-valuemin/valuemax/
valuenow, the full arrow/Home/End/PageUp/PageDown keyboard map, touch
and pointer handling, and form posting. None of it is re-implemented here.
Everything this module adds is paint: a custom track, a primary fill, tick
marks, and an optional value readout.
Single thumb
<.slider name="volume" label="Volume" value={60} value_suffix="%" show_value="inline" />Dual thumb (a range)
Pass min_field and max_field (or values with min_name/max_name).
Two overlaid native inputs post both names, and the fill spans between them.
<.form for={@form} phx-change="filter">
<.slider
min_field={@form[:min]}
max_field={@form[:max]}
min={0}
max={1000}
step={50}
label="Price"
value_prefix="$"
show_value="inline"
/>
</.form>Marks
marks renders labelled stops under the track. An empty label renders a
tick only, so you can mark every step and label a few.
<.slider
name="year"
label="Year"
value={2010}
min={1990}
max={2030}
step={5}
show_value="tooltip"
marks={[
%{value: 1990, label: "1990"},
%{value: 2010, label: "2010"},
%{value: 2030, label: "2030"}
]}
/>Listening for changes without a form
Wrapping the slider in a <.form phx-change="..."> is the usual route, and
the one the playground's price filter takes. When there is no form to hang it
on, the PetalSlider hook also emits a bubbling petal:slider-change
CustomEvent on the wrapper, carrying detail: {value} for a single thumb and
detail: {values: [min, max]} for a dual one:
// app.js
window.addEventListener("petal:slider-change", (event) => {
if (event.target.id !== "volume") return
document.querySelector("audio").volume = event.detail.value / 100
})It bubbles to window, so one listener can serve every slider on the page and
survives LiveView re-rendering the slider itself.
Relationship to the range field types
<.field type="range"> and <.field type="range-dual"> still work and are
not going anywhere in this release, but <.slider> supersedes them: it is
the same native machinery with marks, a value readout, vertical orientation
and sizes on top. Reach for <.slider> in new code.
Summary
Functions
Renders a slider.
Functions
Renders a slider.
Single vs dual mode is inferred: min_field/max_field or values means
dual, otherwise single. Mixing the two raises ArgumentError.
Attributes
field(:any) - a Phoenix.HTML.FormField for single-thumb use; sets name, id and value. Defaults tonil.min_field(:any) - FormField for the lower value; dual-thumb mode when set with max_field. Defaults tonil.max_field(:any) - FormField for the upper value; dual-thumb mode when set with min_field. Defaults tonil.name(:string) - input name when not using field. Defaults tonil.min_name(:string) - lower input name in dual mode when not using min_field; defaults to "#{name}_min". Defaults tonil.max_name(:string) - upper input name in dual mode when not using max_field; defaults to "#{name}_max". Defaults tonil.id(:string) - wrapper id; the inputs derive theirs from it. Defaults tonil.value(:any) - current value (single-thumb). Defaults tonil.values(:list) - [min, max] current values (dual-thumb, when not using min_field/max_field). Defaults tonil.min(:any) - lower bound. Defaults to0.max(:any) - upper bound. Defaults to100.step(:any) - step increment; values snap to it natively. Defaults to1.marks(:list) - labelled stops rendered under the track, e.g. [%{value: 0, label: "Min"}, %{value: 50, label: ""}]; an empty label renders a tick only. Defaults to[].show_value(:string) - tooltip shows the value in a bubble above the thumb while dragging or focus-visible; inline renders it in the label row beside the track. Defaults to"none". Must be one of"tooltip","inline", or"none".value_prefix(:string) - prepended to displayed values, e.g. "$". Defaults to"".value_suffix(:string) - appended to displayed values, e.g. "%". Defaults to"".label(:string) - visible label above the track, and the base for each input's accessible name (dual thumbs become "<label> minimum" and "<label> maximum"); defaults to the humanised field name. Defaults tonil.orientation(:string) - vertical stands the track up, filling from the bottom. Defaults to"horizontal". Must be one of"horizontal", or"vertical".size(:string) - track thickness and thumb diameter. Defaults to"md". Must be one of"sm","md", or"lg".disabled(:boolean) - disables every input and dims the control. Defaults tofalse.class(:any) - CSS class for the outer wrapper. Defaults tonil.- Global attributes are accepted. any other HTML attributes, applied to the wrapper.