Slider

free

Slider selects a number or a range by dragging a thumb along a track.

Preview
Dark
import Slider from '@/components/ui/Slider';

export default function UsageDemo() {
  return (
    <div className="w-full max-w-sm">
      <Slider defaultValue={60} />
    </div>
  );
}

Installation

Add this component with the NateUI CLI.

npx nateui@latest add Slider

Examples

Range

Preview
Dark
import Slider from '@/components/ui/Slider';

export default function RangeDemo() {
  return (
    <div className="w-full max-w-sm">
      <Slider.Range defaultValue={[20, 50]} />
    </div>
  );
}

Disabled

Preview
Dark
import Slider from '@/components/ui/Slider';

export default function DisabledDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-8">
      <Slider disabled defaultValue={60} />
      <Slider.Range disabled defaultValue={[20, 50]} />
    </div>
  );
}

Tooltips

Preview
Dark
Show on hover
Always visible
60
Custom content
import Slider from '@/components/ui/Slider';

export default function TooltipsDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-12">
      <div className="flex flex-col gap-2">
        <span className="text-sm font-medium">Show on hover</span>
        <Slider showTooltipOnHover defaultValue={60} />
      </div>
      <div className="flex flex-col gap-2">
        <span className="text-sm font-medium">Always visible</span>
        <Slider alwaysShowTooltip defaultValue={60} />
      </div>
      <div className="flex flex-col gap-2">
        <span className="text-sm font-medium">Custom content</span>
        <Slider
          showTooltipOnHover
          defaultValue={60}
          tooltip={(value) => `${value}%`}
        />
      </div>
    </div>
  );
}

Marks

Preview
Dark
$20k
$50k
$80k
import Slider from '@/components/ui/Slider';

const marks = [
  { value: 20, label: '$20k' },
  { value: 50, label: '$50k' },
  { value: 80, label: '$80k' },
];

export default function MarksDemo() {
  return (
    <div className="w-full max-w-sm">
      <Slider defaultValue={40} marks={marks} />
    </div>
  );
}

Step

Preview
Dark
0°C
25°C
50°C
75°C
100°C
0°C
26°C
37°C
100°C
import Slider from '@/components/ui/Slider';

const evenMarks = [
  { value: 0, label: '0°C' },
  { value: 25, label: '25°C' },
  { value: 50, label: '50°C' },
  { value: 75, label: '75°C' },
  { value: 100, label: '100°C' },
];

const unevenMarks = [
  { value: 0, label: '0°C' },
  { value: 26, label: '26°C' },
  { value: 37, label: '37°C' },
  { value: 100, label: '100°C' },
];

export default function StepDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-16">
      <Slider
        step={25}
        defaultValue={25}
        marks={evenMarks}
        tooltip={(value) =>
          evenMarks.find((mark) => mark.value === value)?.label
        }
      />
      <Slider
        stepOnMarks
        defaultValue={26}
        marks={unevenMarks}
        tooltip={(value) =>
          unevenMarks.find((mark) => mark.value === value)?.label
        }
      />
    </div>
  );
}

Min And Max

Preview
Dark
import Slider from '@/components/ui/Slider';

export default function MinAndMaxDemo() {
  return (
    <div className="w-full max-w-sm">
      <Slider showTooltipOnHover defaultValue={0} min={-20} max={20} />
    </div>
  );
}

Custom Color

Preview
Dark
import Slider from '@/components/ui/Slider';

export default function CustomColorDemo() {
  return (
    <div className="w-full max-w-sm">
      <Slider
        defaultValue={70}
        classNames={{
          bar: 'bg-linear-to-r from-palette-blue via-palette-purple to-palette-rose',
          thumb: 'border-palette-purple',
        }}
      />
    </div>
  );
}

Controlled

Preview
Dark
Value: 50
Range: 2050
import { useState } from 'react';
import Slider from '@/components/ui/Slider';

export default function ControlledDemo() {
  const [value, setValue] = useState(50);
  const [range, setRange] = useState<[number, number]>([20, 50]);

  return (
    <div className="flex w-full max-w-sm flex-col gap-12">
      <div className="flex flex-col gap-2">
        <Slider value={value} onChange={setValue} />
        <div className="text-sm text-muted-foreground">
          Value: <span className="font-semibold text-foreground">{value}</span>
        </div>
      </div>
      <div className="flex flex-col gap-2">
        <Slider.Range value={range} onChange={setRange} />
        <div className="text-sm text-muted-foreground">
          Range:{' '}
          <span className="font-semibold text-foreground">
            {range[0]} – {range[1]}
          </span>
        </div>
      </div>
    </div>
  );
}

API

Slider selects a single value; Slider.Range selects a [start, end] pair with two thumbs. Both are uncontrolled with defaultValue or controlled with value and onChange, and both accept native div props.

Slider

PropDescriptionTypeDefault
valueCurrent value in controlled mode.number-
defaultValueInitial value when uncontrolled.number0
onChangeFires with the new value while the value changes.(value: number) => void-
onDraggingStopFires with the final value when a drag or key change ends.(value: number) => void-
minLowest selectable value.number0
maxHighest selectable value.number100
stepIncrement applied while dragging or using arrow keys.number1
marksReference points rendered under the track.SliderMark[][]
stepOnMarksSnap the thumb to mark values instead of stepping by step.boolean-
precisionDecimal places kept in the reported value.numberderived from step
tooltipTooltip content, or a function of the current value.SliderTooltipidentity
showTooltipOnHoverShow the tooltip on hover, drag, and focus.booleanfalse
alwaysShowTooltipKeep the tooltip visible at all times.booleanfalse
disabledPrevent interaction and dim the track.booleanfalse
thumbAriaLabelAccessible label for the thumb.string-
nameName of the hidden input holding the value.string-
inputPropsProps spread onto the hidden input.ComponentPropsWithoutRef<'input'>-
classNamesClass names for individual slider parts.SliderClassNames{}
classNameClass names for the root element.string-
refRef forwarded to the root element.Ref<HTMLDivElement>-
...nativePropsNative props for the root div.ComponentProps<'div'>-

Slider.Range

PropDescriptionTypeDefault
valueCurrent range in controlled mode.RangeSliderValue-
defaultValueInitial range when uncontrolled.RangeSliderValue-
onChangeFires with the new range while it changes.(value: RangeSliderValue) => void-
onDraggingStopFires with the final range when a drag or key change ends.(value: RangeSliderValue) => void-
minLowest selectable value.number0
maxHighest selectable value.number100
minRangeSmallest allowed distance between the two thumbs.number0
maxRangeLargest allowed distance between the two thumbs.number-
stepIncrement applied while dragging or using arrow keys.number1
marksReference points rendered under the track.RangeSliderMark[][]
stepOnMarksSnap thumbs to mark values instead of stepping by step.boolean-
precisionDecimal places kept in the reported values.numberderived from step
tooltipTooltip content, or a function of a single thumb value.SliderTooltipidentity
showTooltipOnHoverShow tooltips on hover, drag, and focus.booleanfalse
alwaysShowTooltipKeep both tooltips visible at all times.booleanfalse
disabledPrevent interaction and dim the track.booleanfalse
thumbArialLabelStartAccessible label for the start thumb.string-
thumbAriaLabelEndAccessible label for the end thumb.string-
nameBase name for the hidden -from and -to inputs.string-
inputPropsProps spread onto both hidden inputs.ComponentPropsWithoutRef<'input'>-
classNamesClass names for individual slider parts.RangeSliderClassNames{}
classNameClass names for the root element.string-
refRef forwarded to the root element.Ref<HTMLDivElement>-

Types

type RangeSliderValue = [number, number]
 
type SliderTooltip = ReactNode | ((value: number) => ReactNode)
 
type SliderMark = { value: number; label?: ReactNode }
 
type RangeSliderMark = { value: number; tooltip?: ReactNode }
 
type SliderClassNames = {
  thumb?: string
  bar?: string
  mark?: string | ((isFilled: boolean) => string)
  track?: string
}
 
type RangeSliderClassNames = {
  thumb?: [string, string]
  bar?: string
  mark?: string
  track?: string
}