Charcoal UI

Range Slider

Six sliders that share one accessible core: drag, click, or use the arrow, Page and Home/End keys. Every variant respects reduced motion.

  • Category: Inputs
  • Licence: Free, MIT
  • Built with: React 19, Tailwind CSS 4, Motion
  • Dependencies: motion, clsx, tailwind-merge

Examples

Inline Slider

Label and value live inside the track. Ten stops span the rail; any marker under text hides, and text dims while the thumb passes over it.

Tick Slider

Tick dots and a vertical-bar thumb that bounces as it lands on each step.

Fluid Slider

No thumb. The fill trails on a soft spring with a stretching cap, and the text flips colour wherever the fill covers it.

Wave Slider

Equalizer bars swell around the value while you hover or drag, then settle back.

Bubble Slider

Grab the thumb and a value bubble pops out. It leans and squashes with your drag speed, then settles upright.

Ruler Slider

The ember needle stays put while the scale scrolls under it. Flick it and it glides, then snaps to the nearest tick.

API reference

Inline Slider

PropTypeDefaultDescription
labelstring—Compact label inside the left edge of the track.
format(value: number) => string—Formats the inline value.
showTicksbooleantrue
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

Tick Slider

PropTypeDefaultDescription
labelstring—
format(value: number) => string—
showTicksbooleantrueA dot per step, or 11 evenly spaced dots past 40 steps.
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

Fluid Slider

PropTypeDefaultDescription
labelstring—
format(value: number) => string(v) => `${v}%`
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

Wave Slider

PropTypeDefaultDescription
barsnumber32Number of bars across the track.
labelstring—
format(value: number) => string—
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

Bubble Slider

PropTypeDefaultDescription
format(value: number) => string—
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

Ruler Slider

PropTypeDefaultDescription
gapnumber14Pixels between two steps.
majorEverynumber5Label every Nth step and draw it tall.
unitstring—Shown next to the value.
valuenumber—Controlled value.
defaultValuenumber—Initial value when uncontrolled.
onValueChange(value: number) => void—
minnumber0
maxnumber100
stepnumber1Values snap to this step; readouts keep its decimal precision.
disabledbooleanfalse
aria-labelstring—Required when there is no visible label.
formatValueText(value: number) => string—Announced instead of the raw number, e.g. “72.5 kg”.

About Range Slider

Range Slider is a family of six sliders that share one input engine, so every variant drags, clicks and responds to the keyboard the same way. Pick the look that fits the setting: a compact inline slider for a settings panel, a fluid fill for volume, a ruler with momentum for picking a weight.

Range Slider is an input component for React 19, styled with Tailwind CSS 4 and animated with Motion. It drops into Next.js, Vite, Remix or Astro through the shadcn CLI as a single file you own.

When to use Range Slider

  • Settings and preference panels where a value needs a label and a live readout.
  • Media controls such as volume, brightness or playback speed.
  • Pricing calculators and configurators where the number drives a total.
  • Measurement inputs like weight, height or distance, where the ruler variant feels physical.

How it works

A shared hook handles pointer capture, snapping to the step, and the full keyboard map (arrows, Page Up and Down, Home and End). Each variant only draws: positions follow on springs, readouts keep the step's decimal precision, and the thumb lands with a small bounce when it reaches a new step.

It is a real form control: it has an accessible name, works with the keyboard alone, shows a visible focus ring and announces its state to screen readers. With prefers-reduced-motion on, it holds still or settles instantly instead of animating.

Customizing Range Slider

Every prop is documented in the API reference above with its type and default. The ones you will reach for first are listed here.

The Customize panel next to the preview lets you change label, step, showTicks, disabled, bars and more live, and the Code tab updates to match, so the snippet you copy already carries your values.

  • label (string): Compact label inside the left edge of the track.
  • format ((value: number) => string): Formats the inline value.
  • showTicks (boolean, default true).
  • value (number): Controlled value.
  • defaultValue (number): Initial value when uncontrolled.
  • min (number, default 0).

6 examples on this page

  • Inline Slider: Label and value live inside the track. Ten stops span the rail; any marker under text hides, and text dims while the thumb passes over it.
  • Tick Slider: Tick dots and a vertical-bar thumb that bounces as it lands on each step.
  • Fluid Slider: No thumb. The fill trails on a soft spring with a stretching cap, and the text flips colour wherever the fill covers it.
  • Wave Slider: Equalizer bars swell around the value while you hover or drag, then settle back.
  • Bubble Slider: Grab the thumb and a value bubble pops out. It leans and squashes with your drag speed, then settles upright.
  • Ruler Slider: The ember needle stays put while the scale scrolls under it. Flick it and it glides, then snaps to the nearest tick.

Goes well with Range Slider

Range Slider is already composed into 3 ready-made sections, so you can see it in context or install the whole block.

  • Features Bento: Features section
  • Pricing Usage: Pricing section
  • Pricing Calculator: Pricing section
  • Button: An animated React button with six variants, spring press feedback and a width-stable loading state
  • Switch: An animated React toggle switch whose thumb stretches when pressed, like a real switch
  • Checkbox: An animated React checkbox: the check draws itself in, the box pops, indeterminate morphs to a dash
  • Radio Group: An animated React radio group with roving focus and a highlight that glides between card options
  • Input: An animated React text input with icons, a shake-once error and a success check that draws in

Install Range Slider

npx shadcn@latest add https://charcoalui.com/r/range-slider.json

Range Slider is free and MIT licensed. The command copies range-slider.tsx into components/ui and installs clsx, tailwind-merge; you can also copy the source from the Code tab by hand.

It pairs well with Knob, a Pro piece: Rotary dial with an ember arc. Drag up or down, scroll, or use the arrow keys.

Frequently asked questions

Can I make it a controlled slider?
Yes. Pass value and onValueChange to control it, or defaultValue to let it manage itself. formatValueText changes what screen readers announce, for example "72.5 kg" instead of the raw number.
How do I install Range Slider?
Run npx shadcn@latest add https://charcoalui.com/r/range-slider.json. The shadcn CLI copies range-slider.tsx into components/ui and installs motion, clsx, tailwind-merge. You can also copy the source from this page by hand.
Is Range Slider free for commercial use?
Yes. Range Slider is MIT licensed: use it in any personal or commercial project and change it however you like.
Does Range Slider work with Next.js?
Yes. It is a client component for React 19 styled with Tailwind CSS 4, so it works in the Next.js App Router and Pages Router, Vite, Remix and Astro.
Can an AI coding agent install Range Slider?
Yes. Connect the Charcoal UI MCP server (https://charcoalui.com/mcp) to Claude Code, Cursor or any MCP client; get_component returns Range Slider's props and source and get_install_command returns the exact command.

Range Slider as Markdown · llms.txt