caliper uidocs

Range histogram

Free

A range filter over the shape of the data: bars outside the range dim as you drag, and the count in range is written out.

Installs components/ui/range-histogram.tsxDepends on none beyond ReactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/range-histogram.json

Nightly price

€90 – €320

160 stays in range

When to use #

Use it for

  • Price, size and date filters on large lists.
  • Any range where the spread of values matters.

Skip it when

  • Few values; a select or chips is clearer.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/range-histogram.json

Adds its 3 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 { RangeHistogram } from "@/components/ui/range-histogram"

const prices = Array.from({ length: 320 }, (_, index) => {
  // A right-skewed spread like real prices: a hump of mid-range stays, a long tail.
  const u = ((index * 9301 + 49297) % 233280) / 233280;
  const v = ((index * 4096 + 150889) % 714025) / 714025;
  return Math.round(40 + Math.pow((u + v) / 2, 1.6) * 760);
});

export function RangeHistogramDemo() {
  const money = (value: number) => `€${value}`;
  return <RangeHistogram className="max-w-md" label="Nightly price" values={prices} min={40} max={800} step={10} defaultValue={[90, 320]} format={money} noun="stays" />;
}

API reference #

RangeHistogram

component
PropTypeDefaultDescription
label *string—
values *readonly number[]—Every data point, e.g. each product's price.
min *number—
max *number—
stepnumber1
binsnumber24How many bars to draw.
valuereadonly [number, number]—
defaultValuereadonly [number, number]—
onValueChange((value: [number, number]) => void)—
format((value: number) => string)String
nounstring"results"What is counted, e.g. "homes": "84 homes in range".
classNamestring—

Accessibility #

It is built on native elements and keeps aria-hidden and aria-live in step with state. Changes that matter are announced through a live region.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.