Skip to content
caliper ui docs

Components

Ruler slider

A tape of ticks that slides under a fixed needle. Drag it and let go: it keeps the speed you gave it, slows, and clicks into the nearest step while the number above rolls to the new value. For picking a measurement where the scale itself helps.

Free
pnpm dlx shadcn@latest add @caliper/ruler-slider

Target weight

You can change this later in Health.

68.5kg
40.045.050.055.060.065.070.075.080.085.090.095.0100.0105.0110.0115.0120.0125.0130.0135.0140.0

Drag the ruler, or use the arrow keys.

Installs components/ui/ruler-slider.tsxDepends on none beyond ReactMotion honours reduced motion

When to use

Use it for

  • Physical quantities with a familiar scale: weight, height, distance, temperature.
  • Touch-first settings where a wide sweep beats a small thumb.

Skip it when

  • Exact numbers people already know; a `NumberField` is faster to type into.
  • Ranges or two values at once; use `Slider`.

Decisions

Why it is built this way, so you know what to keep when you change your copy.

Behaviour

The tape moves, not the needle
The value is always under the same point, so the eye stays put and the scale passes beneath it, as on a real tape.
Momentum, then a detent
A flick carries the tape on with friction; the value commits at each step as it passes, and the needle gives a small click when it lands.
Ends you can feel
Dragging past the limits stretches the tape a little and springs back, instead of stopping dead.

Usage

A slider underneath
It is a slider to assistive technology: arrows step, Page keys jump a numbered tick, and the value is read with its unit.

Installation

terminal
pnpm dlx shadcn@latest add @caliper/ruler-slider

Adds its 4 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage

This is the code behind the preview above.

example.tsx
import { useState, type ReactNode } from "react"
import { RulerSlider } from "@/components/ui/ruler-slider"

function Panel({ title, context, className = "max-w-md", children }: { title: string; context: string; className?: string; children: ReactNode }) {
  return (
    <section className={`grid w-full gap-5 rounded-overlay border border-border bg-background p-6 shadow-resting max-sm:p-4 ${className}`}>
      <div className="grid gap-1">
        <p className="font-medium">{title}</p>
        <p className="text-sm text-muted-foreground">{context}</p>
      </div>
      {children}
    </section>
  );
}

export function RulerSliderDemo() {
  const [weight, setWeight] = useState(68.5);
  return (
    <Panel title="Target weight" context="You can change this later in Health.">
      <RulerSlider label="Target weight" unit="kg" min={40} max={140} step={0.5} majorEvery={10} value={weight} onValueChange={setWeight} />
      <p className="text-center text-sm text-muted-foreground">Drag the ruler, or use the arrow keys.</p>
    </Panel>
  );
}

API reference

RulerSlider

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
label *string—Names the value, e.g. "Weight".
valuenumber—
defaultValuenumber—
onValueChange((value: number) => void)—
minnumber0
maxnumber100
stepnumber1
majorEverynumber10A long, numbered tick every this many steps.
unitstring—Shown after the readout, such as "kg".
gapnumber10Pixels between ticks.

Accessibility

It exposes slider semantics, with aria-label, aria-valuemin, aria-valuemax, aria-valuenow, aria-valuetext and aria-hidden kept in step with state.

KeyBehaviour
HomeJumps to the first item or the minimum.
EndJumps to the last item or the maximum.

Motion

It checks prefers-reduced-motion itself and settles immediately instead of travelling. Every state is still reachable.

All Changing values examples