Skip to main content

Slider

Slider is a form control for choosing a number or a range within set bounds, like adjusting volume or filtering by price. It shows the current value in a tooltip, and people drag a handle or use the arrow keys to change it.

Import

import { Slider } from '@vortexlabs/vortex';
import type { SliderProps } from '@vortexlabs/vortex';

Other links

Drag to adjust the volume.
<Stack
  width="320px"
  maxWidth="100%"
>
  <Slider.Root>
    <Slider.Label>Volume</Slider.Label>
  <Slider.Control name="playground-volume" defaultValue={40} />
  <Slider.HelperText>Drag to adjust the volume.</Slider.HelperText>
  <Slider.ErrorMessage>Volume is too high.</Slider.ErrorMessage>
  </Slider.Root>
</Stack>

Features

  • Single values or ranges.
  • Custom bounds and steps.
  • Custom tooltip formatting.
  • Live and final value updates.
  • Horizontal or vertical layout.
  • Helper text, errors, and disabled states.

Anatomy

Root groups the field, Label names it, and Control is the slider and requires name. HelperText is optional.

<Slider.Root>
  <Slider.Label>Volume</Slider.Label>
  <Slider.Control name="volume" />
  <Slider.HelperText>Adjust the playback volume.</Slider.HelperText>
</Slider.Root>

Bounds and Steps

Set min, max, and step to define the available values, and defaultValue to choose the starting point.

Adjust in steps of five.
import { Slider } from "@vortexlabs/vortex";

<Slider.Root>
  <Slider.Label>Volume</Slider.Label>
  <Slider.Control name="volume" min={0} max={100} step={5} defaultValue={40} />
  <Slider.HelperText>Adjust in steps of five.</Slider.HelperText>
</Slider.Root>

Range Selection

Set range and give each handle a minLabel and maxLabel. Use minName and maxName to submit separate form values, or one shared name.

Minimum priceMaximum price
Choose a minimum and maximum price.
<Slider.Root>
  <Slider.Label>Price range</Slider.Label>
  <Slider.Control
    range
    minName="min-price"
    maxName="max-price"
    minLabel="Minimum price"
    maxLabel="Maximum price"
    min={0}
    max={500}
    step={25}
    defaultMinValue={100}
    defaultMaxValue={350}
  />
  <Slider.HelperText>Choose a minimum and maximum price.</Slider.HelperText>
</Slider.Root>

Controlled Values and Commit Events

Use value with onChange to track the value as it changes. onChangeCommit fires once the interaction ends, which suits expensive work like applying a filter.

Current: 40 km. Applied: 40 km.
"use client";

import { Slider } from "@vortexlabs/vortex";
import { useState } from "react";

export const SliderControlledExample = () => {
  const [value, setValue] = useState(40);
  const [committed, setCommitted] = useState(40);
  return (
    <Slider.Root>
      <Slider.Label>Search radius</Slider.Label>
      <Slider.Control
        name="radius"
        min={5}
        max={100}
        step={5}
        value={value}
        onChange={({ value }) => setValue(value)}
        onChangeCommit={({ value }) => setCommitted(value)}
      />
      <Slider.HelperText>
        Current: {value} km. Applied: {committed} km.
      </Slider.HelperText>
    </Slider.Root>
  );
};

Controlled Range

A controlled range takes minValue and maxValue. onChange reports both, so update them together.

Minimum temperatureMaximum temperature
20–70 degrees
"use client";

import { Slider } from "@vortexlabs/vortex";
import { useState } from "react";

export const SliderRangeExample = () => {
  const [range, setRange] = useState({ minValue: 20, maxValue: 70 });
  return (
    <Slider.Root>
      <Slider.Label>Temperature range</Slider.Label>
      <Slider.Control
        range
        name="temperature"
        minLabel="Minimum temperature"
        maxLabel="Maximum temperature"
        min={0}
        max={100}
        minValue={range.minValue}
        maxValue={range.maxValue}
        onChange={({ minValue, maxValue }) => setRange({ minValue, maxValue })}
      />
      <Slider.HelperText>
        {range.minValue}–{range.maxValue} degrees
      </Slider.HelperText>
    </Slider.Root>
  );
};

Value Formatting

Use renderValue to format the tooltip and the value screen readers announce. Pass false to hide the tooltip.

"use client";

import { Slider, Stack } from "@vortexlabs/vortex";

export const SliderFormatExample = () => {
  return (
    <Stack gap={6} width="100%">
      <Slider.Root>
        <Slider.Label>Playback speed</Slider.Label>
        <Slider.Control
          name="playback-speed"
          min={0.5}
          max={2}
          step={0.25}
          defaultValue={1}
          renderValue={({ value }) => value + "× speed"}
        />
      </Slider.Root>
      <Slider.Root>
        <Slider.Label>Background intensity</Slider.Label>
        <Slider.Control name="intensity" defaultValue={30} renderValue={false} />
      </Slider.Root>
    </Stack>
  );
};

Vertical

Set orientation="vertical" and place the slider in a container with a set height.

<Stack height="16rem">
  <Slider.Root>
    <Slider.Label>Volume</Slider.Label>
    <Slider.Control name="vertical-volume" orientation="vertical" defaultValue={60} />
  </Slider.Root>
</Stack>

Disabled and Error States

Set disabled or error on Slider.Root. Slider.ErrorMessage shows only when error is set.

This allocation exceeds your remaining storage.
<Stack gap={6} width="100%">
  <Slider.Root disabled>
    <Slider.Label>Managed volume</Slider.Label>
    <Slider.Control name="managed-volume" defaultValue={50} />
  </Slider.Root>
  <Slider.Root error>
    <Slider.Label>Storage allocation</Slider.Label>
    <Slider.Control name="storage-allocation" defaultValue={90} />
    <Slider.ErrorMessage>This allocation exceeds your remaining storage.</Slider.ErrorMessage>
  </Slider.Root>
</Stack>

Accessibility

Key
Description
Up arrowDown arrowLeft arrowRight arrow
Move the focused handle by one step.
Page UpPage Down
Move the focused handle by a larger, browser-defined step.
HomeEnd
Move the focused handle to its minimum or maximum.
Provide Slider.Label, or an aria-label through inputAttributes, to name the slider.
Provide distinct minLabel and maxLabel when range is set.
Use renderValue when the raw number needs units to make sense.