# Window range

> A time window over a live area chart: drag its edges to resize, drag or flick it to pan with momentum, and the dates roll to their new values.

- Type: Component (inputs)
- Access: Arc Pro
- Page: https://uiarc.dev/components/window-range
- Markdown: https://uiarc.dev/components/window-range/markdown
- Source file: `registry/components/window-range/window-range.tsx`
- Dependencies: motion
- Keywords: input, slider, range, chart, new, date range, time window, brush, range selector, timeline, analytics, sparkline, area chart, trimmer, scrubber, zoom window, report period, momentum, pan

## When to use

- Choosing the date range of an analytics report while seeing the shape of the data behind it.
- Scrubbing a window over usage, revenue or latency to compare periods.
- A compact overview with a movable window above a detailed chart or table.

## When not to use

- Use date-range-picker when people pick exact dates from a calendar or the range spans years.
- Use brush-chart when the window should zoom a large detailed chart and show events in place.
- Use slider or gooey-range for numeric ranges that have no series to show.

## Installation

Window range is part of Arc Pro. The live preview is public; the source and install command need Pro.

### CLI with a Pro token

1. Create a token in your account and set it in the environment (or `.env.local`). Never commit it.

```bash
export ARC_PRO_TOKEN=arc_pro_...
```

2. Add the Pro registry to `components.json`:

```json
{
  "registries": {
    "@uiarc": "https://uiarc.dev/r/{name}.json",
    "@uiarc-pro": {
      "url": "https://uiarc.dev/r/pro/{name}.json",
      "headers": {
        "Authorization": "Bearer ${ARC_PRO_TOKEN}"
      }
    }
  }
}
```

3. Install:

```bash
npx shadcn@latest add @uiarc-pro/window-range
```

### Manual

Signed-in Pro members can copy the source from the Manual tab on the docs page.

- Plans: https://uiarc.dev/pricing
- Create a Pro token: https://uiarc.dev/account#pro-access
- Setup guide: https://uiarc.dev/docs/ai#pro-access

## Usage

```tsx
import { useState } from "react";
import { WindowRange } from "@/components/arc/window-range/window-range";

const day = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" });
const FIRST = Date.UTC(2026, 3, 1);

export function VisitorsReport({ visits }: { visits: number[] }) {
  const last = visits.length - 1;
  const [range, setRange] = useState<[number, number]>([last - 29, last]);

  return (
    <WindowRange
      label="Report dates"
      data={visits}
      value={range}
      onValueChange={setRange}
      onValueCommit={loadReport}
      minSpan={6}
      format={index => day.format(FIRST + index * 86_400_000)}
      formatSpan={span => `${span + 1} days`}
      live
    />
  );
}
```

## API reference

### WindowRange

A time window over a live area chart. Drag either edge of the frame to resize the window, drag inside it to pan and flick to let it coast, or press outside to glide it there. The chart outside the window fades back, the one inside stays in full color, and the start, end and length readouts roll to their new values. New data morphs the chart in place, and a live dot pulses on the latest point.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `data` (required) | `readonly number[]` | – | The series behind the window, one number per point, spread evenly from min to max. Pass a new array to morph the chart to it. |
| `value` | `[number, number]` | – | Controlled window as [start, end] in domain units. Pair with onValueChange. A new value from outside glides the frame there. |
| `defaultValue` | `[number, number]` | `the last quarter` | Starting window when uncontrolled. |
| `onValueChange` | `(value: [number, number]) => void` | – | Runs on every change while dragging, coasting after a flick or pressing keys. |
| `onValueCommit` | `(value: [number, number]) => void` | – | Runs once the window has settled after a drag, a flick or a key. Use it to fetch the report for the window. |
| `min` | `number` | `0` | Start of the domain, for example day 0. |
| `max` | `number` | `data.length - 1` | End of the domain. |
| `step` | `number` | `1` | Both ends snap to this step, counted from min. With one point per day and the default, the window moves in days. |
| `largeStep` | `number` | `a tenth of the domain` | How far Page Up, Page Down and Shift with an arrow move an edge or the window. |
| `minSpan` | `number` | `step` | The narrowest window as end minus start, in domain units. |
| `maxSpan` | `number` | `the whole domain` | The widest window as end minus start, in domain units. |
| `format` | `(value: number) => string` | – | Formats the start and end readouts and the spoken values, for example a day index as Aug 31. |
| `formatSpan` | `((span: number) => string) \| null` | – | Formats the middle readout from end minus start, for example span => `${span + 1} days`. Pass null to hide it. |
| `ticks` | `readonly { value: number; label: string }[]` | – | Labels under the chart, such as the first day of each month. |
| `label` | `string` | `"Date range"` | Names the group and prefixes the names of the start, window and end sliders. |
| `live` | `boolean` | `false` | Pulses a dot on the latest point to show that the series is still arriving. |
| `accent` | `string` | – | Any CSS color for the frame and the line. Defaults to the selection control color for the frame and the first chart series for the line. |
| `height` | `number` | `112` | Height of the chart in px, from 64 to 240. |
| `disabled` | `boolean` | `false` | Dims the control and ignores pointer and keys. |
| `className` | `string` | – | Class on the root element. |
| `style` | `CSSProperties` | – | Inline styles on the root element. |

## Keyboard interactions

| Keys | Action |
| --- | --- |
| Tab | Moves focus to the start edge, the window, then the end edge. |
| Arrow Right / Arrow Left | On an edge, moves that edge by one step. On the window, pans the whole window by one step. |
| Arrow Up / Arrow Down | Same as Arrow Right and Arrow Left. |
| Shift + Arrow, Page Up / Page Down | Moves the edge or the window by the large step. |
| Home / End | On the window, pans it to the start or end of the domain. On an edge, moves it as far as the span limits allow. |

## Accessibility

- The component is a group named by label with three focusable role="slider" elements: the start edge, the window and the end edge.
- Each edge speaks its formatted date, with aria-valuemin and aria-valuemax that respect minSpan and maxSpan. The window speaks both ends, such as Aug 31 to Sep 29, and its range is the start positions it can take.
- The chart, the frame and the rolling readouts are decorative and hidden from assistive technology; the sliders carry every value.
- Pressing into a limit with a key nudges the frame against it instead of failing silently.
- Pointer focus draws no ring; keyboard focus shows Arc's shared focus ring. A pressed part takes focus so keys continue where the pointer left off.

## Motion

- One requestAnimationFrame loop steps the frame's springs at 240 Hz and writes transforms straight to the DOM through a cache; it stops at rest, offscreen and in background tabs.
- Dragging an edge or the window follows the finger one to one with coalesced pointer events. Past either end of the domain, or past the span limits, the frame rubber bands.
- Releasing a pan keeps the measured speed: the landing point is projected from the flick, snapped to a step and reached on a critically damped spring that starts at the flick's speed, so the window decelerates like a scroll view and bumps softly into either end. Grabbing it mid coast stops it where it is.
- A press outside the window glides it to center on the finger on a softer spring; dragging on moves it from there. Keys, presets and new values from props glide the same way.
- The full color chart shows through a clip that is scaled to the window while its content is scaled back, so moving the window never relayouts or repaints the chart; outside it the muted copy shows.
- The readouts roll each changed digit, and month names as a whole word, in the direction of change. During a drag or a coast they update in place so they never trail the frame.
- New data morphs the line and area from the old shape on a smooth spring. The live dot pulses with a compositor animation.
- With reduced motion the frame jumps to each value, there is no coast, rubber band, roll, chart morph or pulse, and every value, key and readout still works.

## Responsive behavior

- The chart and frame fill their container from 320px up. The readouts share one row, with the length in the middle; hide it with formatSpan null in very tight spaces.
- The plot takes the press with touch-action pan-y, so vertical page scroll still works over the chart. The edges have hit areas that reach 14px outward, and the frame never draws narrower than its two edges.
- Tick labels sit under their values; pass fewer ticks at narrow widths.

## Performance

- Moving the window only writes transforms on the frame, the edges and the clip; the chart path is written only when data changes.
- The chart is one SVG path pair drawn twice with a non scaling stroke, so resizing the container needs no recalculation beyond one measure.
- Pointer math reads the plot rectangle once per press, and the loop idles at rest and pauses offscreen with an IntersectionObserver and in background tabs.

## Notes for AI

- Use it to pick a time window over a series people can see: analytics reports, billing usage, logs or metrics. Keep the data to one point per step, a few hundred points at most.
- Map the domain to indices and format them: pass min 0, one data point per day and a format that turns the index into a date. formatSpan receives end minus start, so add one for an inclusive day count.
- Recompute totals in onValueChange for live feedback, and fetch in onValueCommit, which fires once the window settles.
- Pair it with quick range buttons that set value; the frame glides to them and the readouts roll.
- Set live only when the latest point really is still changing.

## Related

- [Brush chart](https://uiarc.dev/components/brush-chart/markdown): A dense time series with an overview strip: drag a window to zoom, resize it by its handles, and read events in place.
- [Date range picker](https://uiarc.dev/components/date-range-picker/markdown): A range picker that grows from its trigger into two months with presets and a stretching range highlight.
- [Sparkline](https://uiarc.dev/components/sparkline/markdown): Show a compact trend beside a value.
- [Line chart](https://uiarc.dev/components/line-chart/markdown): A multi-series line chart with a gliding crosshair, legend toggles, and paths that morph between ranges.
- [Metric card](https://uiarc.dev/components/metric-card/markdown): A compact summary for a number that needs context.

## Also in sliders

- [Slider](https://uiarc.dev/components/slider/markdown): Pick a value or a range on a track that follows your finger.
- [Elastic slider](https://uiarc.dev/components/elastic-slider/markdown): A slider that stretches like rubber past its ends, with a swaying value tag and detents the thumb clicks into.
- [Range histogram slider](https://uiarc.dev/components/range-histogram-slider/markdown): A price range over a live histogram of the data, lighting the bars inside the range and settling on bar edges.
- [Ruler slider](https://uiarc.dev/components/ruler-slider/markdown): A tape of ticks that slides under a fixed needle, with momentum, snapping, and a rolling readout.

## Guidance for AI tools

Window range: A time window over a live area chart: drag its edges to resize, drag or flick it to pan with momentum, and the dates roll to their new values. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://uiarc.dev/llms.txt
