Slider

Slider lets users select a value or range by moving handles along a track.

Basics

Basic slider usage for selecting numeric values within a range.

Loading demo…

import { useState } from 'react'; import { Block, Slider } from '@plocks/ui'; export function Demo() { const [value, setValue] = useState(25); return ( <Block fullWidth> <Slider accessibilityLabel="Volume" value={value} onChange={setValue} /> </Block> ); }

Slider variants

Loading demo…

import { Block, Slider } from '@plocks/ui'; const VARIANTS = ['default', 'filled', 'outline', 'minimal', 'segmented', 'unstyled'] as const; export function Demo() { return ( <Block fullWidth> {VARIANTS.map((variant) => ( <Slider key={variant} label={variant} variant={variant} defaultValue={40} step={5} showTicks={variant === 'segmented'} restrictToTicks={variant === 'segmented'} /> ))} </Block> ); }

Ticks and Marks

Slider with visible tick marks and labeled values for better precision.

Loading demo…

import { Block, Slider } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Slider accessibilityLabel="Milestone" defaultValue={50} restrictToTicks ticks={[ { value: 0, label: 'Min' }, { value: 25 }, { value: 50, label: 'Mid' }, { value: 75 }, { value: 100, label: 'Max' }, ]} /> </Block> ); }

Range Slider

RangeSlider puts two thumbs on one track and its value is a [min, max] tuple, for filters such as price ranges.

Loading demo…

import { useState } from 'react'; import { Block, RangeSlider } from '@plocks/ui'; export function Demo() { const [priceRange, setPriceRange] = useState<[number, number]>([25, 75]); return ( <Block fullWidth> <RangeSlider label="Price range" value={priceRange} onChange={setPriceRange} /> </Block> ); }

Value label customization

valueLabelPosition chooses where the thumb tooltip sits (top / bottom for horizontal, left / right for vertical). valueLabelOffset tunes the gap from the thumb. valueLabelProps accepts any <Text> props — ff, fw, size, c, style — and valueLabelStyle overrides the wrapper Card's style. Set valueLabelAsCard={false} for a flat tooltip with no Card chrome. Both <Slider> and <RangeSlider> accept the same set of props.

Loading demo…

import { Block, Slider, RangeSlider, Text } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Block> <Text variant="small" c="secondary">Bottom</Text> <Slider accessibilityLabel="Value label below" defaultValue={60} valueLabelAlwaysOn valueLabelPosition="bottom" valueLabelOffset={2} /> </Block> <Block> <Text variant="small" c="secondary">Custom text</Text> <Slider accessibilityLabel="Custom label text" defaultValue={72} valueLabelAlwaysOn valueLabelProps={{ ff: 'monospace', fw: '700', size: 'md', c: 'primary', }} /> </Block> <Block> <Text variant="small" c="secondary">Flat</Text> <Slider accessibilityLabel="Flat value label" defaultValue={72} valueLabelAlwaysOn valueLabelAsCard={false} valueLabelStyle={{ backgroundColor: 'rgba(15, 23, 42, 0.92)', paddingHorizontal: 8, paddingVertical: 4, borderRadius: 6, }} valueLabelProps={{ ff: 'monospace', fw: '600', c: '#fff' }} /> </Block> <Block> <Text variant="small" c="secondary">RangeSlider</Text> <RangeSlider accessibilityLabel="Range with labels below" defaultValue={[20, 80]} valueLabelAlwaysOn valueLabelPosition="bottom" valueLabelProps={{ fw: '700', size: 'sm' }} valueLabel={(v, i) => (i === 0 ? `min ${Math.round(v)}` : `max ${Math.round(v)}`)} /> </Block> <Block direction="row" justify="center" gap="xl"> <Block align="center"> <Text variant="small" c="secondary">Left</Text> <Block style={{ height: 200 }}> <Slider accessibilityLabel="Vertical, label left" defaultValue={40} orientation="vertical" valueLabelAlwaysOn valueLabelPosition="left" valueLabelProps={{ fw: '700' }} /> </Block> </Block> <Block align="center"> <Text variant="small" c="secondary">Right</Text> <Block style={{ height: 200 }}> <Slider accessibilityLabel="Vertical, label right" defaultValue={60} orientation="vertical" valueLabelAlwaysOn valueLabelPosition="right" valueLabelProps={{ fw: '700' }} /> </Block> </Block> </Block> </Block> ); }

Decimal steps & precision

The thumb tooltip formats its value from the step: a fractional step like 0.01 shows two decimals, while an integer step rounds to a whole number (trailing zeros are trimmed, so 0.10 reads as 0.1). Pass precision to force a fixed number of decimals regardless of the step.

Loading demo…

import { Block, Slider, Text } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Block> <Text variant="small" c="secondary">step 0.01</Text> <Slider accessibilityLabel="Position" defaultValue={0.25} max={1} step={0.01} valueLabelAlwaysOn /> </Block> <Block> <Text variant="small" c="secondary">step 0.5</Text> <Slider accessibilityLabel="Temperature" defaultValue={21.5} min={16} max={30} step={0.5} valueLabelAlwaysOn /> </Block> <Block> <Text variant="small" c="secondary">precision 2</Text> <Slider accessibilityLabel="Ratio" defaultValue={0.5} max={1} step={0.1} precision={2} valueLabelAlwaysOn /> </Block> </Block> ); }

Slot styling

Each visual layer of the slider is independently customizable: trackStyle and activeTrackStyle for the track halves, thumbStyle for the handle, tickStyle / activeTickStyle for tick marks, and tickLabelProps for tick labels. Per-tick style overrides on individual ticks[i].style win over the global tick styles. Combined with the value-label slot props (valueLabelStyle, valueLabelProps) you can fully reskin the slider without forking it.

Loading demo…

import { Block, Slider, RangeSlider, Text } from '@plocks/ui'; const milestoneTicks = [ { value: 0, label: '0' }, { value: 25, label: '25' }, { value: 50, label: '50' }, { value: 75, label: '75' }, { value: 100, label: '100' }, ]; const milestoneTicksWithHighlight = milestoneTicks.map((t) => t.value === 50 ? { ...t, style: { width: 4, height: 14, backgroundColor: '#facc15', borderRadius: 2, top: 11, }, } : t, ); export function Demo() { return ( <Block fullWidth> <Block> <Text variant="small" c="secondary">Track and thumb</Text> <Slider accessibilityLabel="Track and thumb overrides" defaultValue={35} trackStyle={{ height: 10, borderRadius: 2 }} activeTrackStyle={{ height: 10, borderRadius: 2 }} thumbStyle={{ borderRadius: 4, borderWidth: 0 }} /> </Block> <Block> <Text variant="small" c="secondary">Ticks and tick labels</Text> <Slider accessibilityLabel="Tick styling" defaultValue={50} ticks={milestoneTicks} tickStyle={{ width: 3, height: 10, borderRadius: 1.5, top: 13 }} activeTickStyle={{ width: 3, height: 12, borderRadius: 1.5, top: 12 }} tickLabelProps={{ ff: 'monospace', size: 'xs', fw: '700' }} /> </Block> <Block> <Text variant="small" c="secondary">Per-tick style</Text> <Slider accessibilityLabel="Per-tick override" defaultValue={50} ticks={milestoneTicksWithHighlight} tickStyle={{ width: 3, height: 10, borderRadius: 1.5, top: 13 }} activeTickStyle={{ width: 3, height: 10, borderRadius: 1.5, top: 13 }} tickLabelProps={{ size: 'xs' }} /> </Block> <Block> <Text variant="small" c="secondary">RangeSlider</Text> <RangeSlider accessibilityLabel="Range with slot styling" defaultValue={[20, 80]} ticks={milestoneTicks} activeTrackColor="#a855f7" trackStyle={{ height: 8, borderRadius: 4 }} activeTrackStyle={{ height: 8, borderRadius: 4 }} thumbStyle={{ backgroundColor: '#a855f7', borderColor: '#7e22ce', borderWidth: 2 }} tickStyle={{ width: 2, height: 8, top: 14 }} activeTickStyle={{ width: 2, height: 8, top: 14, backgroundColor: '#a855f7' }} tickLabelProps={{ size: 'xs', c: 'muted' }} valueLabelAlwaysOn valueLabelProps={{ fw: '700', size: 'sm' }} /> </Block> </Block> ); }

Vertical Orientation

Vertical slider orientation for space-efficient layouts and different use cases.

Loading demo…

import { Block, Slider } from '@plocks/ui'; export function Demo() { return ( <Block style={{ height: 200 }}> <Slider accessibilityLabel="Level" defaultValue={60} orientation="vertical" /> </Block> ); }

CustomStyles

Restyle the slider with color, trackSize / thumbSize, and the trackStyle, activeTrackStyle, and thumbStyle overrides. RangeSlider accepts the same props.

Loading demo…

import { Block, RangeSlider, Slider } from '@plocks/ui'; export function Demo() { return ( <Block fullWidth> <Slider label="Success palette" defaultValue={65} color="success" trackSize={12} thumbSize={30} trackStyle={{ opacity: 0.25 }} activeTrackStyle={{ shadowColor: '#34C759', shadowOpacity: 0.35, shadowRadius: 8, shadowOffset: { width: 0, height: 4 }, }} thumbStyle={{ borderColor: '#1F5520', borderWidth: 3 }} /> <RangeSlider label="Warning palette" defaultValue={[20, 80]} color="warning" trackSize={10} thumbSize={26} trackStyle={{ opacity: 0.2 }} activeTrackStyle={{ opacity: 0.55 }} thumbStyle={{ borderColor: '#B45309', borderWidth: 2 }} /> </Block> ); }
Scan to open this page on your phoneplocks.dev/ui/Slider