Slider

Single or dual thumb scrubber with marks, orientation, label, and value chrome. Prefer Number Slider for a compact settings row, and Tick Slider for bound labels with a tick gauge.

Also known as: range slider, dual slider, range scrubber, marked slider, continuous slider

Installation

Install with the CLI, or copy the component source into your project.

Add slider (npm)

npx --yes -p @default-file/ui df-ui add slider

Default

Single value on a 0 to 100 bar track.

Line with label

Line track with a leading icon, label, and percent readout above the track. Use valuePosition footer to move that row below.

Volume
63%

Label below track

valuePosition footer places the label and value row under the track. header keeps them above.

Level
42

Label at track ends

valuePosition start places the label and value beside the track on the left. end places them on the right.

Level
42
Level
42

Label and value across track

valuePosition ends puts the label at the start and the value at the end. ends-reverse flips them.

Level
42
42
Level

Custom format

formatValue replaces the built in number or percent readout.

Duration
8h

Scrub sound

scrubSound plays a smooth tone while dragging. Pitch follows position and level follows drag speed. Off by default.

Scrub
40%

Custom value slot

valueSlot replaces the default readout with any node. Pass a function to receive the current values and compose a Badge, counter, or other control. Placement still follows valuePosition.

Level
Score42

Horizontal range

Two thumbs on a line track. Pass two values to enable range mode. Readout shows low to high.

Range
30 to 70

Constrained range

Dual thumbs with minStepsBetween keeping a minimum gap. Optional description can explain the constraint; omit it to hide the copy.

Constrained Range
Minimum gap: 10
52 to 73

Progress

Line track with the value in a bubble above the thumb. Label stays in the header.

Progress

Price range

Dual thumbs with currency values under each handle. valuePosition thumbs keeps the label in the header.

Price Range

Step buttons

Outline icon buttons beside a line track. stepButtonSteps sets how many steps each click moves; here it is 5.

Quantity
50

Vertical range

Bar and line vertical dual thumb ranges side by side. Value stack sits under the track. Minimum sits at the bottom.

Range
79to27
Range
79to27

Vertical marks

Default keeps label above value with marks on the end. The line example uses value-first and marksSide start to flip the stack and sides.

Intensity
Intensity25%
Intensity
50%Intensity

Horizontal marks

Snaps to evenly spaced stops under a line track. Header shows the label and live value.

Level
50

Thickness

thickness scales the track and thumb. sm is fine, md is default, lg is a thick rail.

Thin
60%
Default
60%
Thick
60%

Disabled

Root disabled state. Same treatment for bar or line, range, marks, bubble, and step buttons.

Properties

Single or dual thumb scrubber with bar or line chrome, horizontal or vertical orientation, and optional label, leading icon, and value readout. Prefer Number Slider for a compact settings row, and Tick Slider for bound labels with a tick gauge. Without marks, the thumb tracks the pointer smoothly while dragging and commits to step. With marks, the value snaps to the nearest mark.

Slider

PropTypeDefaultNotes
minnumber0Minimum value.
maxnumber100Maximum value.
stepnumber1Increment between committed values when marks are omitted. Values of 0 or less fall back to 1. With marks, step still controls readout precision unless formatValue is set.
valuenumber[]-Controlled value. One entry is a single thumb. Two entries enable a range with minimum and maximum thumbs. Values are snapped to step, ordered low to high, and clamped.
defaultValuenumber[][min]Uncontrolled initial value. Pass two numbers for a range slider.
onValueChange(value: number[]) => void-Called when a committed value changes. Receives one or two stepped values.
variant"bar" | "line""bar"Track chrome. bar is a filled pill track. line is a thin mute rail with a thicker active segment and circular thumbs.
orientation"horizontal" | "vertical""horizontal"Track direction. vertical places the minimum at the bottom and stacks the range readout under the track.
thickness"sm" | "md" | "lg""md"Track and thumb thickness. sm is fine, md is the default, lg is a thick rail. Remaps the slider thickness tokens on the root. Style overrides of those variables still win.
minStepsBetweennumber0Minimum gap between thumbs in range mode, measured in steps (value gap is minStepsBetween times step). With marks, the gap is counted in mark indices. Use with description to explain the constraint.
marksArray<number | { value: number; label?: React.ReactNode }>-Discrete snap stops. When set, dragging and keyboard move between marks only. Labels render beside a vertical track or under a horizontal track. Omit label to show the formatted value. Prefer a stable array reference.
valuePosition"auto" | "header" | "footer" | "start" | "end" | "ends" | "ends-reverse" | "thumb" | "thumbs" | "bubble""auto"Where the label and value chrome sit. header is above the track. footer is below the track with the same label and value row. start places both beside the track at the start. end places both at the end. ends puts the label at the start and the value at the end, with the track between them. ends-reverse flips that (value at the start, label at the end). auto uses thumb for a vertical marked single thumb, footer for other vertical sliders, and header for horizontal. thumb is vertical single-thumb only; on horizontal or range it falls back to header. thumbs places a formatted value under each thumb and keeps label, leading, and description in the header. bubble floats a tooltip on a single thumb and keeps label, leading, and description in the header.
thumbValueOrder"label-first" | "value-first""label-first"Stack order for traveling thumb meta when valuePosition is thumb. label-first puts the label above the value. value-first puts the value above the label.
marksSide"start" | "end""end"Which side mark labels sit on for a vertical slider. end keeps marks on the right and thumb meta on the left. start swaps them. Ignored for horizontal marks, which stay under the track.
labelReact.ReactNode-Optional heading. In the header by default. For vertical marked sliders it travels with the thumb when valuePosition is thumb or auto.
descriptionReact.ReactNode-Optional supporting line under the label. Omit it to hide the copy while keeping constraints such as minStepsBetween.
leadingReact.ReactNode-Optional leading content before the label, such as an icon. Travels with the thumb when valuePosition is thumb.
showStepButtonsbooleanfalseShow outline icon buttons that decrease and increase the active thumb. Distance per click follows stepButtonSteps. Keyboard arrows still move one step. In range mode, buttons follow the last focused or dragged thumb.
stepButtonStepsnumber1How many step increments each step button applies. With step 1, 5 moves by 5. With marks, hops that many mark stops. Does not change keyboard step size. Values below 1 are treated as 1.
showValueboolean-Show the value slot. Defaults to true when label, description, leading, valueSlot, formatValue, or formatValues is set. Set false to keep a label without a readout. Placement follows valuePosition.
valueFormat"number" | "percent""number"Built in readout format when valueSlot, formatValue, and formatValues are omitted. number uses step precision. percent shows position across min to max.
valueSlotReact.ReactNode | ((values: number[]) => React.ReactNode)-Custom value slot for header, footer, start, end, ends, ends-reverse, and thumb chrome. Replaces the default readout with any node, such as a Badge or counter. Pass a render function to receive the current values and keep the slot in sync. Does not replace per-thumb thumbs or bubble readouts. Overrides formatValues, formatValue, and valueFormat for display. Keyboard and aria valuetext still use formatValue or valueFormat.
formatValue(value: number) => string-Formats each thumb value for the default readout, per-thumb thumbs and bubble text, and aria valuetext. Overrides valueFormat. Ignored for chrome display when valueSlot is set.
formatValues(values: number[]) => React.ReactNode-Custom readout for the full value array when valueSlot is omitted. String and number results keep the default value typography. Other React nodes are treated as custom slot content. Prefer valueSlot for a dedicated Badge or counter.
scrubSoundbooleanfalsePlay a smooth scrub tone while dragging a thumb with the pointer. Pitch follows position and level follows drag speed. Off by default. Stops on release, unmount, or when the document is hidden. Skipped when reduced motion is preferred. Separate from the Tick Slider step tick.
disabledboolean-Blocks pointer, keyboard, marks, and step buttons for every variant and layout.
aria-labelstring-Accessible name. For a range, each thumb appends Minimum or Maximum.
aria-labelledbystring-ID of a labeling element. Defaults to the label element when label is set.
classNamestring-Additional styles on the root.
styleReact.CSSProperties-Inline styles on the root. Can also override Slider CSS variables directly.
refReact.Ref<HTMLDivElement>-Ref to the root element.

Tokens

thickness remaps track, line, and thumb variables to the sm or lg companions. variant line uses the line thickness tokens. valuePosition bubble uses the bubble tokens and reserves clearance on the rail or control. valuePosition start, end, ends, and ends-reverse place chrome in a track row beside the rail using --df-slider-step-gap. orientation vertical uses --df-slider-vertical-size for track length and --df-slider-vertical-column-gap between meta, track, and marks. Horizontal marks use --df-slider-marks-gap. Prop and style overrides still win.

TokenTypeDefaultNotes
--primaryCSS colorvar(--df-neutral-850, var(--df-neutral-900))Active fill (both variants) and bar thumb border.
--foregroundCSS colorvar(--df-neutral-900)Label text, leading icon, and line thumb border.
--mutedCSS colorvar(--df-neutral-50)Bar track background.
--muted-foregroundCSS colorvar(--df-neutral-500)Value readout text.
--backgroundCSS colorvar(--df-neutral-0)Thumb fill.
--df-slider-track-heightCSS lengthcalc(3 * var(--spacing-unit))Bar track thickness for thickness md.
--df-slider-line-track-heightCSS lengthcalc(1 * var(--spacing-unit))Line mute rail thickness for thickness md.
--df-slider-line-range-heightCSS lengthcalc(2 * var(--spacing-unit))Line active segment thickness for thickness md.
--df-slider-line-track-bgCSS colorcolor-mix(in oklch, var(--foreground) 16%, transparent)Mute rail fill for the line variant.
--df-slider-thumb-sizeCSS lengthvar(--df-affordance-size-sm)Thumb size for thickness md.
--df-slider-track-height-smCSS lengthcalc(2 * var(--spacing-unit))Bar track thickness for thickness sm.
--df-slider-line-track-height-smCSS lengthcalc(0.5 * var(--spacing-unit))Line mute rail thickness for thickness sm.
--df-slider-line-range-height-smCSS lengthcalc(1 * var(--spacing-unit))Line active segment thickness for thickness sm.
--df-slider-thumb-size-smCSS lengthvar(--df-affordance-size-xs)Thumb size for thickness sm.
--df-slider-track-height-lgCSS lengthcalc(5 * var(--spacing-unit))Bar track thickness for thickness lg.
--df-slider-line-track-height-lgCSS lengthcalc(2 * var(--spacing-unit))Line mute rail thickness for thickness lg.
--df-slider-line-range-height-lgCSS lengthcalc(4 * var(--spacing-unit))Line active segment thickness for thickness lg.
--df-slider-thumb-size-lgCSS lengthvar(--df-affordance-size-md)Thumb size for thickness lg.
--df-slider-vertical-sizeCSS lengthcalc(48 * var(--spacing-unit))Vertical track length.
--df-slider-marks-gapCSS lengthcalc(2 * var(--spacing-unit))Gap between the horizontal track and the marks row.
--df-slider-vertical-column-gapCSS lengthcalc(5 * var(--spacing-unit))Gap between thumb meta, the vertical track, and mark labels.
--df-slider-marks-track-heightCSS lengthcalc(4 * var(--spacing-unit))Height of the horizontal marks row.
--df-slider-vertical-marks-min-widthCSS lengthcalc(10 * var(--spacing-unit))Minimum width of the vertical marks column.
--df-slider-bubble-pad-inlineCSS lengthcalc(2 * var(--spacing-unit))Horizontal padding inside the value bubble.
--df-slider-bubble-pad-blockCSS lengthcalc(0.75 * var(--spacing-unit))Vertical padding inside the value bubble.
--df-slider-bubble-offsetCSS lengthcalc(2 * var(--spacing-unit))Gap between the thumb and the value bubble.
--df-slider-bubble-radiusCSS lengthvar(--radius-md)Corner radius of the value bubble.
--df-slider-bubble-clearanceCSS lengthcalc(var(--df-slider-thumb-size) + var(--df-slider-bubble-offset) + var(--df-text-11) + (2 * var(--df-slider-bubble-pad-block)))Space reserved above or beside the track for the value bubble. Scales with thumb size, bubble padding, and type size.
--df-slider-thumb-value-clearanceCSS lengthcalc(5 * var(--spacing-unit))Height reserved under a horizontal track for per-thumb values.
--df-slider-thumb-value-columnCSS lengthcalc(12 * var(--spacing-unit))Width reserved beside a vertical track for per-thumb values.
--df-slider-thumb-value-gapCSS lengthcalc(1.5 * var(--spacing-unit))Gap between the track and per-thumb values.
--df-slider-step-gapCSS lengthcalc(2.5 * var(--spacing-unit))Gap between step buttons and the track.
--df-slider-header-gapCSS lengthcalc(2 * var(--spacing-unit))Gap between header, track, and footer.
--df-slider-header-inline-gapCSS lengthcalc(2 * var(--spacing-unit))Gap between the heading block and the header value.
--df-slider-tight-gapCSS lengthcalc(0.5 * var(--spacing-unit))Tight stack gap for heading block, value stack, and thumb meta.
--df-slider-value-sep-mixCSS percentage72%Mix amount for the range separator against muted foreground.
--df-slider-label-gapCSS lengthcalc(1.5 * var(--spacing-unit))Gap between leading content and the label.
--df-slider-leading-sizeCSS lengthcalc(4 * var(--spacing-unit))Leading icon box size.