Slider

Slider is a component to provide input with a drag handle.

basic-demo

Usage#

import { Slider } from '@primereact/ui/slider';
<Slider.Root>
    <Slider.Track>
        <Slider.Range />
    </Slider.Track>
    <Slider.Thumb />
</Slider.Root>

Examples#

Step#

Size of each movement is defined with the step property.

step-demo
import { Slider } from '@primereact/ui/slider';

export default function StepDemo() {
    return (
        <Slider.Root defaultValue={20} step={20} className="max-w-3xs mx-auto w-full">
            <Slider.Track>
                <Slider.Range />
            </Slider.Track>
            <Slider.Thumb />
        </Slider.Root>
    );
}

Range#

Slider provides two handles to define two values. In range mode, value should be an array instead of a single value.

range-demo
import { Slider } from '@primereact/ui/slider';

export default function RangeDemo() {
    return (
        <Slider.Root defaultValue={[20, 80]} className="max-w-3xs mx-auto w-full">
            <Slider.Track>
                <Slider.Range />
            </Slider.Track>
            <Slider.Thumb index={0} />
            <Slider.Thumb index={1} />
        </Slider.Root>
    );
}

Thumbs Distance#

thumbs-distance-demo
import { Slider } from '@primereact/ui/slider';

export default function ThumbsDistanceDemo() {
    return (
        <Slider.Root defaultValue={[20, 80]} className="max-w-3xs mx-auto w-full" minStepsBetweenThumbs={20}>
            <Slider.Track>
                <Slider.Range />
            </Slider.Track>
            <Slider.Thumb index={0} />
            <Slider.Thumb index={1} />
        </Slider.Root>
    );
}

Vertical#

Default layout of slider is horizontal, use orientation property for the alternative vertical mode.

vertical-demo
import { Slider } from '@primereact/ui/slider';

export default function VerticalDemo() {
    return (
        <div className="flex justify-center h-56 gap-4">
            {Array.from({ length: 8 }).map((_, index) => (
                <Slider.Root defaultValue={50} orientation="vertical" key={index}>
                    <Slider.Track>
                        <Slider.Range />
                    </Slider.Track>
                    <Slider.Thumb />
                </Slider.Root>
            ))}
        </div>
    );
}

Disabled#

When disabled is present, the element cannot be edited and focused.

Disabled Slider
Disabled All Thumbs
Disabled Single Thumb
disabled-demo
import { Slider } from '@primereact/ui/slider';

export default function DisabledDemo() {
    return (
        <div className="max-w-3xs w-full mx-auto space-y-12">
            <div>
                <h5 className="mb-2 text-sm font-medium">Disabled Slider</h5>
                <Slider.Root defaultValue={50} disabled>
                    <Slider.Track>
                        <Slider.Range />
                    </Slider.Track>
                    <Slider.Thumb />
                </Slider.Root>
            </div>

            <div>
                <h5 className="mb-2 text-sm font-medium">Disabled All Thumbs</h5>
                <Slider.Root defaultValue={[20, 80]} disabled>
                    <Slider.Track>
                        <Slider.Range />
                    </Slider.Track>
                    <Slider.Thumb index={0} />
                    <Slider.Thumb index={1} />
                </Slider.Root>
            </div>

            <div>
                <h5 className="mb-2 text-sm font-medium">Disabled Single Thumb</h5>
                <Slider.Root defaultValue={[20, 80]}>
                    <Slider.Track>
                        <Slider.Range />
                    </Slider.Track>
                    <Slider.Thumb index={0} disabled />
                    <Slider.Thumb index={1} />
                </Slider.Root>
            </div>
        </div>
    );
}

Controlled#

controlled-demo
'use client';
import { InputNumberValueChangeEvent } from '@primereact/types/shared/inputnumber';
import { SliderRootChangeEvent } from '@primereact/types/shared/slider';
import { InputNumber } from '@primereact/ui/inputnumber';
import { Slider } from '@primereact/ui/slider';
import * as React from 'react';

export default function ControlledDemo() {
    const [value, setValue] = React.useState(50);

    return (
        <div className="max-w-3xs w-full mx-auto">
            <InputNumber value={value} onValueChange={(e: InputNumberValueChangeEvent) => setValue(e.value as number)} fluid className="mb-4" />
            <Slider.Root value={value} onValueChange={(e: SliderRootChangeEvent) => setValue(e.value as number)} className="w-full">
                <Slider.Track>
                    <Slider.Range />
                </Slider.Track>
                <Slider.Thumb />
            </Slider.Root>
        </div>
    );
}

Value Change#

onValueChange: 50
onValueChangeEnd: 50
value-change-demo
'use client';
import type { SliderRootChangeEvent } from '@primereact/types/shared/slider';
import { Slider } from '@primereact/ui/slider';
import * as React from 'react';

export default function ValueChangeDemo() {
    const [value, setValue] = React.useState(50);
    const [endValue, setEndValue] = React.useState(50);

    return (
        <div className="max-w-3xs mx-auto w-full flex flex-col items-center space-y-4">
            <div className="text-sm text-surface-500 font-mono">onValueChange: {value}</div>

            <div className="text-sm text-surface-500 font-mono"> onValueChangeEnd: {endValue}</div>
            <Slider.Root
                value={value}
                onValueChange={(e: SliderRootChangeEvent) => setValue(e.value as number)}
                onValueChangeEnd={(e: SliderRootChangeEvent) => setEndValue(e.value as number)}
                className="w-full"
            >
                <Slider.Track>
                    <Slider.Range />
                </Slider.Track>
                <Slider.Thumb />
            </Slider.Root>
        </div>
    );
}

Custom#

custom-demo
'use client';
import { VolumeUp } from '@primeicons/react';
import type { SliderTrackInstance } from '@primereact/types/shared/slider';
import { Slider } from '@primereact/ui/slider';

export default function CustomDemo() {
    return (
        <div className="max-w-xs mx-auto w-full space-y-16">
            <Slider.Root defaultValue={50}>
                <Slider.Track className="h-2 bg-blue-100 dark:bg-blue-950">
                    <Slider.Range className="bg-blue-500" />
                </Slider.Track>
                <Slider.Thumb className="before:hidden border-2 border-blue-500 bg-surface-0 dark:bg-surface-900 rotate-45 rounded-md" />
            </Slider.Root>

            <Slider.Root defaultValue={50}>
                <Slider.Track className="h-2 bg-amber-100 dark:bg-amber-950">
                    <Slider.Range className="bg-amber-500" />
                </Slider.Track>
                <Slider.Thumb className="before:hidden w-4 h-5 border-2 border-amber-500 bg-surface-0 dark:bg-surface-900 rounded-sm" />
            </Slider.Root>

            <Slider.Root defaultValue={50} className="h-8 rounded-full ">
                <Slider.Track className="h-full rounded-full border border-surface-100 dark:border-surface-900 bg-surface-100 dark:bg-surface-800">
                    {({ slider }: SliderTrackInstance) => {
                        return (
                            <>
                                <VolumeUp className="text-surface-400 absolute left-2 top-1/2 -translate-y-1/2 z-10" />
                                <Slider.Range
                                    className="rounded-full bg-surface-0"
                                    style={{ width: `clamp(2rem, calc(${slider?.state.value}% + 1rem), 100%)` }}
                                >
                                    <Slider.Thumb
                                        style={{ insetBlockStart: '50%', insetInlineStart: 'auto', insetInlineEnd: '0', translate: '0 -50%' }}
                                        className="z-20 h-[calc(100%+2px)]! dark:h-full! aspect-square! w-auto! before:hidden! bg-surface-0 border border-surface-200 rounded-full shadow-sm"
                                    />
                                </Slider.Range>
                            </>
                        );
                    }}
                </Slider.Track>
            </Slider.Root>

            <Slider.Root defaultValue={50}>
                <Slider.Track className="h-8 flex! items-center gap-1 w-full bg-transparent cursor-grab active:cursor-grabbing">
                    {({ slider }: SliderTrackInstance) => {
                        return (
                            <>
                                <span
                                    className="bg-linear-to-r from-sky-200 via-indigo-200 to-blue-400 h-full rounded-full"
                                    style={{ width: `calc(${slider?.state.value}% - 1.25rem)` }}
                                />
                                <Slider.Thumb
                                    style={{ insetInlineStart: 'auto', translate: 'auto' }}
                                    className="relative! before:hidden size-8! shrink-0 bg-surface-0 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 rounded-full shadow-sm"
                                />
                                <span
                                    className="h-full bg-surface-100 dark:bg-surface-900 rounded-full"
                                    style={{ width: `calc(100% - ${slider?.state.value}% - 1.25rem)` }}
                                />
                            </>
                        );
                    }}
                </Slider.Track>
            </Slider.Root>
        </div>
    );
}

Filter#

Image filter implementation using multiple sliders.

user header
filter-demo
'use client';
import { SliderRootChangeEvent } from '@primereact/types/shared/slider';
import type { ToggleButtonGroupValueChangeEvent } from '@primereact/types/shared/togglebuttongroup';
import { Slider } from '@primereact/ui/slider';
import { ToggleButton } from '@primereact/ui/togglebutton';
import { ToggleButtonGroup } from '@primereact/ui/togglebuttongroup';
import Image from 'next/image';
import * as React from 'react';

export default function FilterDemo() {
    const [filter, setFilter] = React.useState(0);
    const [filterValues, setFilterValues] = React.useState([100, 100, 0]);

    const filterStyle = React.useMemo(() => {
        return {
            filter: `contrast(${filterValues[0]}%) brightness(${filterValues[1]}%) sepia(${filterValues[2]}%)`
        };
    }, [filterValues]);

    return (
        <div className="flex flex-col items-center justify-center">
            <Image
                alt="user header"
                className="w-80 rounded mb-6"
                src="https://primefaces.org/cdn/primevue/images/card-vue.jpg"
                style={filterStyle}
                width={320}
                height={240}
            />
            <ToggleButtonGroup value={filter} onValueChange={(e: ToggleButtonGroupValueChangeEvent) => setFilter(e.value as number)}>
                <ToggleButton.Root value={0}>
                    <ToggleButton.Indicator>Contrast</ToggleButton.Indicator>
                </ToggleButton.Root>
                <ToggleButton.Root value={1}>
                    <ToggleButton.Indicator>Brightness</ToggleButton.Indicator>
                </ToggleButton.Root>
                <ToggleButton.Root value={2}>
                    <ToggleButton.Indicator>Sepia</ToggleButton.Indicator>
                </ToggleButton.Root>
            </ToggleButtonGroup>
            <Slider.Root
                value={filterValues[filter]}
                onValueChange={(e: SliderRootChangeEvent) =>
                    setFilterValues((prev) => {
                        const updated = [...prev];

                        updated[filter] = e.value as number;

                        return updated;
                    })
                }
                className="w-56 mt-4"
                min={0}
                max={200}
            >
                <Slider.Track>
                    <Slider.Range />
                </Slider.Track>
                <Slider.Thumb />
            </Slider.Root>
        </div>
    );
}

Accessibility#

Screen Reader#

Slider element component uses slider role on the handle in addition to the aria-orientation, aria-valuemin, aria-valuemax and aria-valuenow attributes. Value to describe the component can be defined using aria-labelledby and aria-label props.

Keyboard Support#

KeyFunction
tabMoves focus to the slider.
left arrow / up arrowDecrements the value.
right arrow / down arrowIncrements the value.
homeSet the minimum value.
endSet the maximum value.
page upIncrements the value by 10 steps.
page downDecrements the value by 10 steps.