Brush

Time-range brush for zooming area and line charts with a mini-chart strip and draggable selection handles

Installation

ChartBrush and ChartBrushLayout ship with time-series charts. Install the area chart (or line chart) registry item, then import from your charts package:

import {
  AreaChart,
  Area,
  ChartBrush,
  ChartBrushLayout,
  Grid,
  XAxis,
  ChartTooltip,
} from "@/components/charts";

Usage

Wrap the main chart in ChartBrushLayout. Render a simplified mini chart in brushStrip with ChartBrush as a child. Pass xDomain, xDomainSlotCount, and tweenYDomainOnXDomainChange to the main chart so it zooms and tweens the y-scale as the brush changes.

<ChartBrushLayout
  data={data}
  enabled
  height={72}
  brushStrip={(layout) => (
    <AreaChart
      animationDuration={0}
      data={data}
      status="ready"
      style={{ aspectRatio: "unset", height: "100%" }}
    >
      <Area dataKey="value" fillOpacity={0.15} animate={false} showHighlight={false} />
      <ChartBrush
        initialSelection={layout.brushSelection ?? undefined}
        onSelectionChange={layout.onBrushSelectionChange}
      />
    </AreaChart>
  )}
>
  {(layout) => (
    <AreaChart
      data={data}
      tweenYDomainOnXDomainChange
      xDomain={layout.xDomain}
      xDomainSlotCount={layout.xDomainSlotCount}
      yDomainTween
    >
      <Grid horizontal />
      <Area dataKey="value" fillOpacity={0.35} />
      <XAxis />
      <ChartTooltip />
    </AreaChart>
  )}
</ChartBrushLayout>

Works the same with LineChart and Line in the brush strip and main chart. See Area Chart and Line Chart for chart-specific notes.

Open Studio with brush enabled to tune strip height, blur, fade edges, and selection pattern.

ChartBrushLayout

Orchestrates the main chart and optional brush strip. Owns brush selection state and derives xDomain for the main chart.

PropTypeDefaultDescription
dataRecord<string, unknown>[]requiredFull dataset for the brush strip and main chart
xDataKeystring"date"Key in data for x-axis values
enabledbooleanrequiredWhen false, children render without brush zoom
heightnumberrequiredBrush strip height in pixels
brushStrip(layout) => ReactNodeMini chart + ChartBrush below the main chart
children(layout) => ReactNoderequiredMain chart render function
classNamestringWrapper class name

The layout argument provides:

FieldTypeDescription
xDomain[Date, Date] | undefinedVisible x-range for the main chart
xDomainSlotCountnumber | undefinedFull dataset length for x-scale padding
brushSelection{ start: Date; end: Date } | nullCurrent brush window
onBrushSelectionChange(selection) => voidPass to ChartBrush onSelectionChange

ChartBrush

Renders inside a time-series chart (typically the brush strip). Drag handles to pan and resize; the main chart zooms via ChartBrushLayout.

PropTypeDefaultDescription
onSelectionChange(domain) => voidFires while dragging with the selected date range
initialSelection{ start: Date; end: Date }Initial brush window
selection{ start: Date; end: Date }Controlled selection
brushDirection"horizontal" | "vertical" | "both""horizontal"Brush axis
blurPxnumber1.5Backdrop blur on dimmed track (0–5 px)
fadeOuterEdgesbooleantrueFade dimmed regions at outer track edges
selectionPattern{ preset; color }Pattern fill inside the selection window
useWindowMoveEventsbooleantrueUse window move events (recommended for brush strips)

Selection pattern presets

selectionPattern.preset accepts: diagonal, horizontal, vertical, cross, dots, or accent. Omit selectionPattern for a solid selection fill.

Main chart props

When brush zoom is active, pass these to AreaChart or LineChart:

PropTypeDefaultDescription
xDomain[Date, Date]Visible x-range from layout.xDomain
xDomainSlotCountnumberlayout.xDomainSlotCount (full data length)
tweenYDomainOnXDomainChangebooleanfalseTween y-domain when the brush changes the visible range

CSS variables

VariableDefaultDescription
--chart-brush-bordervar(--chart-grid)Brush handle border color