Components / Charts

BrushChart

A dense time series with an overview strip: drag a window to zoom, resize it by its handles, and read events in place.

Install

npx shadcn@latest add https://irisui.dev/r/brush-chart.json
import { BrushChart } from "@/components/iris/brush-chart/brush-chart";
Registry item brush-chartBrings in foundationRegistry JSON

Preview

BrushChart

A dense time series with an overview strip: drag a window to zoom, resize it by its handles, and read events in place.

When to use

  • Long daily or hourly histories (months to years) where people need the whole picture and a close look at any stretch: active users, requests, revenue per day.
  • Marking launches, incidents and pricing changes with short annotations that show on both the plot and the overview.
  • Linking range presets (30D, 90D, 1Y) or other charts to the window through a controlled range.
  • Not for a few weeks of data, multiple series or values below zero; use LineChart. The value axis starts at zero, so it suits counts and totals better than prices.

Usage

import { BrushChart } from "@/components/iris/brush-chart/brush-chart";

function ActiveUsers({ days }) {
  // [{ date: epochMs, value: 3240 }, ...] ascending
  const last = days[days.length - 1].date;
  const [range, setRange] = React.useState([days[days.length - 90].date, last]);
  return h(BrushChart, {
    data: days,
    label: "MyRoomie daily active users",
    unit: "users",
    range,
    onRangeChange: setRange,
    annotations: [
      { date: Date.UTC(2026, 2, 24), label: "Profile Boost", description: "Profile Boost from €2.99/week" },
    ],
  });
}

Props

Prop Type Default Description
data { date: Date | number; value: number }[] required Points in ascending time order.
label string required Names the chart for assistive technology.
unit string "" Unit after values in the tooltip and table.
formatValue / formatTick / formatDate functions compact ticks Tooltip values, value axis, dates in tooltip and announcements.
annotations { date; label; description? }[] [] Event markers on both charts. Keep labels to a word or two.
range [number, number] — Controlled window in epoch ms; a new value glides the window there.
defaultRange [number, number] whole series Initial window when uncontrolled.
onRangeChange (range) => void — Fires while the window is dragged, resized, stepped or reset.
minSpan number 7 days Smallest window in ms.
height / overviewHeight number 240 / 52 Main plot and overview strip heights.
emptyLabel string "No data yet" Shown with fewer than two points.
className string — Class on the root figure.
ref Ref<HTMLElement> — Forwarded to the root figure.

Notes

  • Keyboard: on the plot, Left/Right move the crosshair. On the window, Left/Right pan a tenth (Shift or Page keys pan half), +/- zoom around the centre. On a handle, Left/Right move that edge one point (Shift: ten). Home/End go to the ends; Escape or 0 resets to the whole series.
  • Accessibility: the window and both handles are sliders with dates in aria-valuetext; the plot is a focusable group whose readings include any event that day; a hidden table lists the points in the window. Markers carry a text label, not colour alone.
  • Reads --series-1 for the line and area, --series-2 for event markers, --line and --line-strong for the grid.