Xzero UI
Pro library

Horizon chartPro

A horizon chart that stacks fourteen daily series as compact folded rows, with a synced crosshair, a sort by name, peak or latest, a band count setting that folds every row on one spring, and a legend that explains how to read the bands.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/horizon-chart
Live · keyboard ready

Render <HorizonChart /> for the demo, or pass series (signed values against a baseline, one per day), days and ticks, plus baselineLabel for the legend. defaultSort, defaultBands and extent set the opening view; onSortChange, onBandsChange and onDayChange report changes.

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/horizon-chart

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { HorizonChart } from "@/components/xzero/blocks/horizon-chart/horizon-chart";

export function MarketHealth({ markets, days }) {
  return (
    <HorizonChart
      title="Sessions against baseline"
      series={markets}
      days={days}
      baselineLabel="spring average"
      defaultBands={3}
      onDayChange={index => setInspectedDay(index)}
    />
  );
}

API reference

HorizonChart

A horizon chart that stacks many daily series as compact rows. Each row folds its curve into bands of rising intensity, one hue above the baseline and one below, so a dozen series fit in the height of two line charts. A synced crosshair reads every row on the same day, rows sort by name, peak swing or latest value on one spring, a band count setting folds and unfolds every row together, and a legend explains how to read the bands.

PropTypeDefaultDescription
seriesHorizonSeries[]horizonSeriesOne row per series: an id, a name and one value per day as a signed distance from its baseline (12 means 12% above, -8 means 8% below).
daysHorizonDay[]horizonDaysDays on the shared x axis, oldest first, each with a short label and a long label for the readout and screen readers.
ticks{ index: number; label: string }[]horizonMonthTicksLabels on the x axis, each placed at a day index.
titlestring"Sessions against baseline"Heading of the block.
descriptionstringhorizonDescriptionLine under the title. Pass an empty string to hide it.
baselineLabelstring"spring average"What the values are measured against, used in the legend caption and for screen readers.
defaultSort"name" | "peak" | "latest""peak"Opening row order. Peak sorts by the largest swing from baseline in either direction, latest by the value on the last day.
defaultBands1 | 2 | 3 | 43Opening number of bands each row folds into. One band draws a plain area chart.
extentnumber–Distance from the baseline that fills every band; larger values stay in the strongest band. Defaults to the largest value rounded up to a multiple of 12, so every band count has a round step.
formatValue(value: number) => stringsigned whole percentFormats a value for the rows, the legend and screen readers. The default uses a true minus sign.
onSortChange(sort: HorizonSort) => void–Called after the row order changes.
onBandsChange(bands: 1 | 2 | 3 | 4) => void–Called after the band count changes.
onDayChange(index: number | null) => void–Called when the synced crosshair moves to a day, or with null when it clears.
classNamestring–Class on the root element.

Keyboard interactions

KeysAction
TabMoves to the sort switch, the band count switch and the chart.
Arrow keysOn a switch, moves the selection. On the chart, moves the crosshair one day left or right.
Shift + Arrow left / rightOn the chart, moves the crosshair one week.
Home / EndOn the chart, jumps to the first or last day.
EscapeOn the chart, clears the crosshair and shows the latest day again.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Guidance for AI tools

Blocks are complete, self-contained screens with sample data. Replace the sample data and connect the callbacks described above. 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://ui.xzero.co.uk/llms.txt

Browse all components