Skip to content

Area Chart

A trend over time: a smooth line with a gradient fill, plus LineChart for comparing series without fills.

Preview

Revenue this year

$328,700

12 points, Jan to Dec. Revenue: low $18,400, high $38,700, last $38,700.

Revenue by month
MonthRevenue
Jan$18,400
Feb$21,200
Mar$19,800
Apr$24,600
May$23,100
Jun$27,900
Jul$26,400
Aug$31,200
Sep$29,800
Oct$34,500
Nov$33,100
Dec$38,700

Installation

pnpm add @syntara/react @syntara/tokens
import { AreaChart, LineChart } from '@syntara/react';

Usage

import { AreaChart } from '@syntara/react';

export function Revenue({ data }: { data: { month: string; revenue: number }[] }) {
  return (
    <AreaChart
      aria-label="Revenue by month"
      data={data}
      x="month"
      series={[{ key: 'revenue', label: 'Revenue' }]}
      format={{ value: { style: 'currency', currency: 'USD', maximumFractionDigits: 0 } }}
    />
  );
}

Examples

Two series

Overlapping areas with a legend; the readout lists every series at that x.

  • Income
  • Spending

8 points, W1 to W8. Income: low $3,900, high $6,100, last $5,900. Spending: low $2,900, high $4,100, last $3,500.

Income and spending by week
WeekIncomeSpending
W1$4,200$3,100
W2$3,900$3,600
W3$5,100$2,900
W4$4,700$3,800
W5$5,600$3,300
W6$5,200$4,100
W7$6,100$3,700
W8$5,900$3,500

Line chart

LineChart with three series and dots on each point.

  • Web
  • iOS
  • Android

7 points, Mon to Sun. Web: low 980, high 1,520, last 980. iOS: low 860, high 1,310, last 1,310. Android: low 720, high 1,080, last 1,080.

Active users by platform, last 7 days
DayWebiOSAndroid
Mon1,240860720
Tue1,380910780
Wed1,310990810
Thu1,4601,040900
Fri1,5201,120940
Sat1,0901,2601,010
Sun9801,3101,080

Minimal

Linear curve, no grid and no y axis, for a compact trend.

8 points, 09:00 to 16:00. Requests: low 320, high 690, last 690.

Requests per hour today
HourRequests
09:00320
10:00410
11:00385
12:00520
13:00470
14:00610
15:00580
16:00690

Table view

A switch that shows the chart's data table.

4 points, Q1 to Q4. Balance: low €12,400, high €19,300, last €19,300.

Savings balance by quarter
QuarterBalance
Q1€12,400
Q2€15,800
Q3€14,900
Q4€19,300

Accessibility

KeysAction
TabMoves focus into the chart (one tab stop), to the last point you visited or the first.
ArrowRightorArrowLeftMoves to the next / previous x position and shows its readout. Mirrored in right-to-left locales.
HomeorEndJumps to the first / last x position.
EscapeHides the readout without moving focus (WCAG 1.4.13). The next move shows it again.
  • The plot's hit layer is a React Aria ListBox (horizontal): one option per x position, named with its x and every series value, e.g. "Mar: Revenue $19,800, Costs $13,100". Focusing an option makes the screen reader read it, so no live region is needed.
  • The ListBox is named by aria-label or aria-labelledby (one is required) and described by a one-sentence summary (generated from the data, or the summary prop).
  • Every chart also renders its data as a <table> with a caption, visually hidden unless showTable. No value is only reachable by hovering.
  • The SVG, axis labels and the floating readout are aria-hidden: they repeat what the options and the table say.
  • Pointer, pen and touch snap to the nearest x position (full-height bands), so nobody has to land on a 2px line or a thin bar.
  • Text never wears a series colour: labels, axes, legend and readout use text.default and text.subtle; the series colour is only on marks and swatches. Series colours come from --syntara-chart-1..4, solved per brand and scheme to reach 3:1 on surfaces and stay distinguishable under colour-vision deficiency.
  • A 2px focus ring surrounds the plot and axes while an x position has keyboard focus.
  • Motion (line draw-in, area fade-up, bar growth, readout glide) sits behind prefers-reduced-motion: no-preference.
  • There are no disabled or invalid states: a chart is read-only.

Guidelines

Do

  • Name the chart with aria-labelledby when a card title already says what it shows.
  • Use AreaChart for one or two series over time; LineChart when comparing three or four.
  • Format values with Intl options so the readout, table and names read naturally in every locale.
  • Pass null for a missing value: the line breaks instead of dropping to zero.

Don’t

  • Don't plot more than 4 series; fold the tail into "Other" or use small multiples.
  • Don't put two y scales on one chart; index both series to a common base or use two charts.
  • Don't colour text with series colours; the legend and readout already key each series.
  • Don't rely on the chart alone for a number that matters; state it in a heading or stat.

API reference

AreaChart

aria-label | aria-labelledbyRequired
string

Names the chart. One is required; use aria-labelledby to point at a visible card title.

dataRequired
T[]

One object per x position, in order.

xRequired
keyof T

Key of the x value in each row (a month name, a Date, a number).

seriesRequired
{ key: string; label: string; color?: string }[]

What to plot, in palette order (--syntara-chart-1..4). Up to 4; past that, fold the tail into "Other". color overrides the palette with a token.

format
{ value?: Intl.NumberFormatOptions | fn; axis?: …; x?: Intl.DateTimeFormatOptions | fn }

Formats values (readout, table, names), y ticks (default: value in compact notation) and x values (Dates default to "12 Mar").

height
number

Height of the plot plus the x axis, in px. The legend sits above it.

Default 240

curve
  • smoothdefault
  • linear

smooth is monotone cubic: it never overshoots the data, so a peak is never drawn higher than it was.

showGrid
boolean

Horizontal hairlines at each y tick.

Default true

showXAxis
boolean

X labels, thinned to what fits (always the first and last).

Default true

showYAxis
boolean

Y tick labels in a gutter at the inline start.

Default true

yDomain
[number, number]

Fixes the y range. Default: nice round numbers around the data, from 0 for areas; fitted for LineChart.

showLegend
boolean

Legend above the plot.

Default series.length > 1

showTable
boolean

Shows the data table under the chart instead of keeping it visually hidden.

Default false

xLabel
string

Header of the table's first column, e.g. "Month".

summary
string

One sentence describing the data for screen readers. Default: generated from the data.

glow
boolean

A soft halo in the series colour under each line. Decorative.

Default true

showDots
boolean

Ringed dots on every data point.

Default false

LineChart

…
AreaChartProps

Same props as AreaChart. No fill, and the y range is fitted to the data instead of starting at 0.

Tokens

The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.

Colour8
text.defaulttext.subtleborder.defaultborder.subtlesurface.raisedfocus.ringtext.brandaccent.text
Type6
font.bodyfont.size.xsfont.size.smfont.tracking.xsfont.tracking.smfont.weight.semibold
Space and size4
space.1space.2space.3space.4
Shape3
radius.containerradius.fieldradius.pill
Depth4
hairlineshadow.overlayshadow.highlightshadow.raised
Motion7
motion.duration.fastmotion.duration.normalmotion.duration.slowmotion.easingmotion.easingOutmotion.springmotion.duration.spring
Other6
chart.1chart.2chart.3chart.4chart.gridchart.axis