Range
Slider input
Intent
Range is a slider for selecting a numeric value within a
defined min / max -- volume, brightness, opacity, weight,
any continuous numeric setting where direct manipulation
beats a typed number. It styles a native
<input type="range"> with
appearance: none and rebuilds the track and
thumb via vendor pseudo-elements, normalizing the visual
across Chrome, Safari, Edge, and Firefox.
Reach for a numeric input when the user needs to type a precise value, when the valid range is unbounded or very large, or when the readout matters more than the manipulation. Range is for feel, not precision.
Basic usage
Add class="input" to a native
<input type="range">. Provide
min, max, and an initial
value; step is optional and
defaults to 1.
<div class="stack">
<label for="demo-vol">Volume</label>
<input id="demo-vol" type="range" class="input" min="0" max="100" value="50"/>
</div>Variants
Size
Track height and thumb size scale together so the thumb stays vertically centered at every size.
<div class="stack">
<label for="demo-sm">Small</label>
<input id="demo-sm" type="range" class="input is-sm" min="0" max="100" value="25"/>
<label for="demo-default">Default</label>
<input id="demo-default" type="range" class="input" min="0" max="100" value="50"/>
<label for="demo-lg">Large</label>
<input id="demo-lg" type="range" class="input is-lg" min="0" max="100" value="75"/>
</div>Tick marks via <datalist>
A <datalist> linked to the range via
the list attribute remains useful even
though brio doesn't paint its tick marks visually:
browsers that support snap-to-step still snap the
thumb to the datalist's option values, and assistive
tech can read the
<option>'s label
attribute to announce stops as the user navigates.
Markup pattern:
<input id="vol" type="range" class="input"
min="0" max="100" value="50" step="5"
list="vol-stops">
<datalist id="vol-stops">
<option value="0" label="Mute"></option>
<option value="50" label="Half"></option>
<option value="100" label="Full"></option>
</datalist>
Why ticks aren't visually rendered.
brio's custom chrome stripes the slider's native
rendering with appearance: none so the
track and thumb can be styled to match the rest of the
input family. The browser's tick-mark drawing is part
of that native rendering -- when we strip it, the
ticks go too. The trade-off is the same one Bootstrap,
Tailwind, and most CSS systems make: visual chrome
consistency in exchange for the native ticks.
If you need visible ticks, render them
in adjacent markup below the slider -- a
.cluster.is-between of small text labels
spaced at the option positions reads more clearly than
thin tick lines anyway, and you get to position the
labels precisely. The
<datalist> can stay (still useful
for snap-step and ARIA) while the visual labels live
externally.
<div class="stack is-tight">
<label for="demo-ticks">Volume</label>
<input id="demo-ticks" type="range" class="input" min="0" max="100" value="50" step="5" list="demo-tick-marks"/>
<datalist id="demo-tick-marks">
<option value="0" label="Mute"></option>
<option value="25"></option>
<option value="50" label="Half"></option>
<option value="75"></option>
<option value="100" label="Full"></option>
</datalist>
<div class="cluster is-between text-muted text--1" aria-hidden="true">
<span>Mute</span>
<span>Half</span>
<span>Full</span>
</div>
</div>State and interaction
- Hover -- thumb border darkens, signalling the thumb as the interactive target before any click.
- Focus (keyboard): thumb border
shifts to
--color-primaryand a focus ring appears around the thumb. Mouse focus (clicking the thumb) is intentionally unstyled -- the thumb's position is the feedback. Arrow keys increment / decrement the value bystep; Page Up / Page Down jump by a larger amount; Home / End go to min / max. - Disabled -- the input fades to 50% opacity and pointer is disallowed.
<div class="stack">
<label for="demo-disabled">Disabled</label>
<input id="demo-disabled" type="range" class="input" min="0" max="100" value="40" disabled=""/>
</div>Visual language
Range matches the rest of the input family in tone -- same surface as text inputs, checkboxes, and radios; primary reserved for focus. The thumb border is thicker than the family default because the thumb is a floating element on a track, not a contained box -- a single-width neutral outline disappears against a light page. There is no filled-portion progress fill: the thumb's position is the indicator. There is no box-shadow on the thumb; brio is flat throughout.
Class reference
.input-- the universal form-input class. On a<input type="range">brio applies the slider chrome described above. Without the class, the browser default renders..input.is-sm,.input.is-lgon the range input -- size variants. Track height and thumb size scale together.
Customization
Hover and focus states drive
--input-range-thumb-border-color through
cascade, so overriding it once recolors every state
automatically. Range styling lives in
src/css/input.css alongside the rest of
the form-input family; the range section sits after the
toggle switch.
Accessibility
-
Always pair with a label. An
unlabeled slider has no accessible name -- screen
readers announce only the value. Use
<label for="...">with a matchingid, or wrap the input in a label, or setaria-labelon the input if no visible label fits the design. -
Announce the current value when relevant.
For sliders whose value matters to surrounding
content (a brightness slider that previews live, a
price filter that updates a listing), pair the
range with a value display
(
<output>bound viafor) oraria-valuetextwhen the raw number isn't meaningful (e.g., a quality slider with named stops). - Don't use range for binary or low-cardinality choices. A slider with only two or three steps is harder to use accurately than a checkbox / radio group / select with the same options. Range is for ranges.
-
Forced-colors mode. Under
@media (forced-colors: active)brio reverts the slider to native rendering (appearance: auto) so high-contrast users get the OS's accessible chrome rather than our custom paint -- which can lose contrast in some palettes. Same fallback as checkbox and radio.
CSS Reference: Input Range
For input range reference see the input page