Skip to content

Components · Charts

LineChart

Line and area charts for trends: multiple series, gaps, reference lines, crosshair tooltip on hover, touch and keyboard, legend toggles and a data table.

@rookcom/monarch-react/chartsComponent

Two series with a previous period and a target

Sessions

Last 14 days against the previous 14

Use the arrow keys to inspect values.
Sessions
DayThis periodPrevious period
Mar 1820672
Mar 2932764
Mar 3901739
Mar 4934766
Mar 51,2901,058
Mar 61,3301,091
Mar 71,3201,082
Mar 81,180968
Mar 91,2501,025
Mar 101,4001,148
Mar 111,3801,132
Mar 121,4601,197
Mar 131,5101,238
Mar 141,4901,222

Usage examples

Area with gaps

Two charts sharing one crosshair

Purpose

Shows how one or more measures change over time or across ordered categories, with exact values one hover, tap or arrow key away and the full data as a table.

Use when

  • A trend over days, weeks or months: traffic, sign-ups, revenue, latency.
  • Comparing a few series on the same scale, or a period against the previous one (dashed).
  • Showing a target, baseline or SLA against the trend (referenceLines).

Avoid when

  • Comparing unordered categories: use BarChart.
  • A trend inside a table cell or stat card: use Sparkline.
  • Two measures on different scales: draw two charts with a shared activeIndex instead of a second axis.

Design principles

  • One value axis. Different scales get separate charts, synced through activeIndex, never a dual axis.
  • Gaps are honest: a missing value breaks the line instead of drawing a fake segment, and a lone point gets a dot.
  • Recessive grid and axes, 2px lines, colour slots in fixed order; colours follow the series, so hiding one never repaints the rest.
  • Exact values on demand (tooltip), not on every point.
  • Every number and date goes through Intl with the locale prop.

API reference

import { LineChart } from '@rookcom/monarch-react/charts';
ExportKindRenderingRoot class
LineChartcomponentclient.mn-chart

Renders ChartFrame (ref to its <figure>); every ChartFrame prop except children, legend and table passes through, and LineChart builds the legend and table from series and data.

data is an array of plain objects; xKey names the x field (Date, number or label) and each series key names a numeric field. Missing, null or non-finite values are gaps.

Pass locale when rendering on the server so server and browser format numbers and dates the same way.

Generated from the TypeScript declarations of packages/react/src/components/charts/line-chart.

Properties

LineChart

Line and area chart for trends over time or ordered categories, with multiple series, gaps, reference lines, a shared crosshair tooltip on hover, touch and keyboard, legend toggles and an accessible data table.

PropTypeDescription
data requiredreadonly ChartDatum[]Rows in x order. Each has the `xKey` field and one number per series; a missing or `null` value is a gap.
series requiredreadonly ChartSeries[]The measures to draw. Two to five read best; colours follow the order unless pinned.
title requiredReactNodeThe chart's name. Labels the figure. Required.
xKey requiredstringField holding the x value: a `Date`, a number or a category label.
actionsReactNodePeriod or metric controls in the header, such as a pill TabsFilter or a Select.
activeIndexnumber | nullControlled inspected index (`null` for none), for a crosshair shared by charts on the same x values. Leave undefined for uncontrolled.
classNamestring
curveCurve`linear` (default) joins points with straight lines; `monotone` smooths without overshooting.
defaultHiddenSeriesreadonly string[]Uncontrolled initial hidden series.
defaultShowTablebooleanUncontrolled initial table view. Default `false`.
descriptionReactNodeOne line under the title: the period, unit or what the chart answers. Describes the figure.
dotsbooleanDraw a dot on every point. Default `false` (lone points between gaps always get one).
emptyActionsReactNodeActions in the empty state, such as a link to set up tracking.
emptyDescriptionReactNodeEmpty-state description, such as what will appear and when.
footerReactNodeNotes under the chart: source, last updated, a footnote.
formatTickValueFormatterFormats value-axis ticks. Default: compact notation of `valueFormat` (1.2K).
formatValueValueFormatterFormats values in the tooltip, table and summary. Wins over `valueFormat`.
formatX((value: XValue, index: number) => string)Formats x values everywhere (axis, tooltip, table, summary). Wins over `xFormat`.
headingLevelChartFrameHeadingLevelRender the title as a heading (`h2`–`h6`) to match the page outline. Default: not a heading.
heightnumberHeight reserved for the chart body (loading, empty and error keep it, so nothing jumps). Default 240.
hiddenSeriesreadonly string[]Controlled list of hidden series keys.
idstring
includeZerobooleanKeep zero on the value axis. Default `true`; turn off for values far from zero.
labelsLineChartLabels
legendTogglebooleanLegend entries toggle their series. Default `true` (legend shows for two or more series).
localestringBCP 47 locale for numbers and dates. Pass it when rendering on the server.
onActiveIndexChange((index: number | null) => void)
onHiddenSeriesChange((hidden: string[]) => void)
onPointSelect((datum: ChartDatum, index: number) => void)Click, Enter or Space on the inspected point, for drill-in.
onRetry(() => unknown)Error-state retry. Return the refetch promise to keep the button busy until it settles.
onShowTableChange((showTable: boolean) => void)
referenceLinesreadonly ChartReferenceLine[]Dashed horizontal lines for targets, baselines or SLAs.
showTablebooleanControlled table view.
statusChartFrameStatus`ready` (default) shows the chart; `loading` a skeleton with `aria-busy`; `empty` an empty state; `error` an error with Try again when `onRetry` is set. Exposed as `data-status`.
summarystringReplaces the generated text summary (the plot's accessible name).
tableTogglebooleanShow the "View as table" toggle. Default `true` when `table` is set.
valueFormatIntl.NumberFormatOptions`Intl.NumberFormat` options for values in the tooltip, table and summary.
variantLineChartVariant`line` (default) or `area`: the line plus a soft fill to the baseline. Exposed as `data-variant`.
xFormatIntl.DateTimeFormatOptions`Intl.DateTimeFormat` options for date x values. Default `{ month: 'short', day: 'numeric' }`.
xLabelstringColumn header for the x values in the data table. Default: `xKey`.
xScaleChartXScale`time` spaces points by their date or number (gaps in time show); `category` spaces them evenly. Default: `time` when every x is a Date or number.
yDomainreadonly [ChartDomainBound, ChartDomainBound]Fix either end of the value axis, e.g. `[0, 100]` for percentages.

Variants

PropValuesDescription
variant'line''area'area adds a soft fill from each line to the baseline. Exposed as data-variant.
curve'linear''monotone'monotone smooths the line without overshooting the data.
xScale'time''category'time (default when every x is a Date or number) spaces points by value, so uneven dates show; category spaces them evenly.
series[].dashed'true''false'A dashed line as a second encoding: previous period, forecast.
dots'true''false'A dot on every point; by default only lone points and the inspected point.

States

StateExposed asBehaviour
Inspecting–Crosshair, enlarged dots on each visible series and a tooltip with every visible value at that x.
Series hiddenaria-pressed="false" on the legend toggleThe series leaves the plot and the y range; it stays in the data table.
Emptydata-status="empty"No rows: ChartFrame shows its empty state.
Loading / errordata-statusPass status (and onRetry); the frame keeps the chart height.
Focus–The plot shows the Monarch focus ring on :focus-visible.

Interaction behaviour

  • Hovering or tapping the plot inspects the nearest point; the tooltip flips to stay inside the chart.
  • Moving the mouse out clears it; a tap keeps the last position until the next tap.
  • Legend entries toggle their series (legendToggle), controlled with hiddenSeries or uncontrolled with defaultHiddenSeries.
  • activeIndex + onActiveIndexChange share one crosshair between charts with the same x values.
  • onPointSelect runs on click, Enter or Space at the inspected point, for drill-in.

Keyboard support

KeysAction
TabFocuses the plot (one tab stop) and inspects the first point.
ArrowRight / ArrowDownNext point.
ArrowLeft / ArrowUpPrevious point.
Home / EndFirst or last point.
PageUp / PageDownMoves a tenth of the points.
EscapeHides the tooltip.
Enter / SpaceCalls onPointSelect for the inspected point.

Accessibility

Role
figure (ChartFrame); the plot is a group with aria-roledescription "chart"
Accessible name
The figure is named by title; the plot by a generated summary (points, then low / high / latest per series, then reference lines) or summary.
  • The SVG is aria-hidden; the summary, a live region and the data table carry the information.
  • While inspecting with the keyboard, a polite live region announces "Mar 4: Sessions 1,204, Previous 988".
  • The tooltip is visual only (aria-hidden), so pointer hovering does not flood screen readers.
  • A hint ("Use the arrow keys to inspect values.") is the plot's description.
  • The data table lists every series, hidden ones included, with row and column headers.
  • Series differ by label and, where set, dash pattern, not by colour alone.
  • Every string, including the summary sentences, is translatable through labels.

Responsive behaviour

  • The chart measures its container (ResizeObserver) and lays out at that width, so text never scales; it works down to 320px.
  • X labels thin out to keep about 72px between them; the first and last stay.
  • Before the width is known (server render, first paint) it draws at 640px scaled to fit, so the markup matches on hydration.
  • Touch: tap to inspect; vertical page scrolling stays available (touch-action: pan-y).

Theme support

  • Series use --mn-color-data-1 … -5, contrast-checked per theme; a sixth series and later fall back to the neutral slot.
  • Grid, ticks, crosshair and reference lines use border and text tokens; the tooltip uses the raised surface and shadow.
  • Light, dark and high-contrast themes follow the tokens with no extra CSS. Reduced motion: the only motion is the tooltip fade, which uses duration tokens that become 0ms.

Do and don't

Do

  • Pin color on series that a filter can remove, so colours follow the entity.
  • Use dashed for a comparison period or forecast, so it differs by more than colour.
  • Pass locale (and xFormat with timeZone for dates) for consistent server and client output.
  • Fold a sixth series and beyond into "Other", or split the chart.

Don't

  • Put two measures with different units on one chart; use two charts with a shared activeIndex.
  • Replace gaps with zeros: a missing day is not a zero day.
  • Label every point; the tooltip and table carry exact values.
  • ChartFrame: The frame LineChart renders; use it directly for custom charts.
  • BarChart: Comparisons across categories or discrete periods.
  • Sparkline: A tiny trend without axes, for tables and cards.
  • StatCard: One headline number with its trend.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsChartFrame

Hand-written SVG with no charting library (docs/adr/0010-charts-rendering-and-colour.md). Scales, paths, tooltip, legend and axes come from src/internal/charts.

Testing coverage

  • One line per series, legend, generated summary, keyboard hint; no axe violations.
  • Keyboard: Tab focuses the plot and inspects the first point; arrows, Home, End, Escape; live region announces; leaving clears the tooltip.
  • Hover inspects the nearest point with a crosshair and flipped tooltip, without announcing; leaving clears it.
  • Gaps split the path and a lone point gets a dot; a single series has no legend.
  • Legend toggle hides a series (uncontrolled) and keeps the other colour; controlled hiddenSeries and activeIndex.
  • onPointSelect from Enter and click.
  • Locale-aware numbers and dates (de-DE currency and long month).
  • Area, monotone curve, dots and reference lines (also in the summary); fixed y domain and custom summary.
  • Empty data shows the empty state; loading passes through; the table lists every series.
  • Renders on the server at the fallback width.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/line-chart; Cross-browser axe: /components/line-chart

Tests: packages/react/src/components/charts/line-chart