DocumentationComponentsTheme Creator
Theme CreatorGitHubIntroduction
InstallationUsageThemingMotion
Components
ChartArea ChartBar ChartLine ChartLive Line ChartComposed ChartPie ChartFunnel ChartRadar ChartRadial ChartSankey ChartScatter ChartCandlestick ChartSunburst ChartChoropleth ChartActivity Heatmap
AI agentsContributing
  1. Components
  2. Area Chart

Area Chart

Token-driven area chart built on Recharts v3 with gradient fills, stacking, single and multi-series support, and full light/dark theming via chart tokens.

$ pnpm add @tessinaui/ui

When to use

  • The amount under the line matters. An area chart is a line chart filled down to its baseline, and the fill says this is an amount: revenue, traffic, storage used over time.
  • Parts that add up to a total. stacked shows how the series sum; expand turns each step into 100%, so the chart reads as share.
  • A range rather than a value. Pass [low, high] pairs to draw a band, such as a normal range or a forecast envelope.
  • A trend inside a stat card. Switch the chrome off and the chart reads as a sparkline.
  • A continuous x-axis. Dates and timestamps suit it; the fill assumes the points are joined.

When not to use

  • When the shape of the line is the point. A trend where the amount does not matter, or whose axis should not start at zero, is a LineChart.
  • To compare categories. Use a BarChart.
  • For parts of one whole with no time axis. Use a PieChart.
  • For several overlapping series. Unstacked fills cover each other; past two or three series, a LineChart reads better.
  • When readers must read exact values. Stacked bands are hard to compare precisely; use a Table beside or instead of the chart.
  • For a single data point. Show it as a number, not a chart.
  • For an area read against bars or a line. A backlog behind weekly totals, or a forecast range behind a projection, is a ComposedChart.

Installation

Terminal
pnpm add @tessinaui/ui recharts

Usage

example.tsx
import { AreaChart } from "@tessinaui/ui";
import type { ChartConfig } from "@tessinaui/ui";

const config: ChartConfig = {
  desktop: { label: "Desktop", color: "var(--chart-1)" },
  mobile: { label: "Mobile", color: "var(--chart-2)" },
};

const data = [
  { month: "Jan", desktop: 186, mobile: 80 },
  { month: "Feb", desktop: 305, mobile: 200 },
  { month: "Mar", desktop: 237, mobile: 120 },
];

<AreaChart data={data} config={config} categoryKey="month" />

Series colours come from the --chart-1 … --chart-6 tokens, referenced as var(--chart-N) in each config entry. They are brand-led, contrast-checked in both modes, and recolour automatically when the theme flips — no JS re-render.

On a phone the legend and the axis take their height out of the chart's 2:1 box. size="lg" gives the plot more room, and startEndOnly keeps the x-axis to its first and last label.

Examples

Default

A single series with the softest natural curve and a brand-tone gradient fill.

Multiple Series

Two series in brand tones with a legend; the areas overlap rather than stack.

Stacked

Two series stacked into a cumulative area, with each solid contour separating the bands.

Expanded

Three series normalised to 0–100% proportional bands with expand.

Curve

linear joins points with straight segments; step holds each value until the next.

Axes

Both axes labelled, values formatted, and the chart given an accessible name and summary.

Reference lines and bands

Recharts children compose straight through: a shaded band for the weekend, a dashed goal line with its own label.

Range band

A [low, high] pair plots a band between two bounds — a normal range, a forecast envelope — with the actual reading drawn over it.

Missing data

A null leaves a gap. connectNulls bridges it with a straight segment interpolated between the surrounding readings — a value nobody measured, drawn in the same stroke as the data. Only correct when a gap genuinely means "unchanged".

Negative values

Values crossing zero, with a reference line marking the baseline.

Sparklines

Every piece of chrome turned off, so the chart reads as a trend line inside a stat card.

Interactive

A time-range control filtering the data, with a running total above the plot.

Choosing a month

With selectionMode="single" a click or a tap over a month, or Enter or Space on the month the arrow keys are on, chooses it; choosing it again clears it. The chosen period keeps the hover band, each area's dot on it wears a ring at the area's top, and its tick becomes the inverse chip, so the choice reads without colour. Here the readout above the chart follows the chosen month.

On a coloured plate

Inside a coloured Surface the chart's chrome takes the plate's ink with no prop: tick text, axis titles, grid lines, the hover cursor, the legend and the focus ring. Series colours are yours. The --chart-N tokens are measured against the page, not a plate, so give each series the plate's ink (hsl(var(--surface-ink))) and tell series apart with dashedSeries and a matching legend icon. Keep text off the fill: a label drawn over an area sits on a wash of the ink, which costs it contrast. The tooltip is a page panel, so it keeps the page's look.

States

The loading skeleton and the empty state shown side by side.

API Reference

Props

PropTypeDefaultDescription
dataAreaChartDatum[]—Row-per-category data. A value may be a [low, high] pair for a banded area.
configChartConfig—Series metadata (label, color, icon).
categoryKeystring—Datum key for the x-axis.
seriesstring[]all config keysWhich series to plot.
curve"monotone" | "natural" | "linear" | "step""monotone"Interpolation.
stackedbooleanfalseStack series cumulatively.
expandbooleanfalseNormalise the stack to 0–100% bands. Implies stacked.
fill"gradient" | "solid""gradient"Fade toward the baseline, or a flat wash.
fillOpacitynumber0.25Top stop opacity of the fill.
connectNullsbooleanfalseBridge null gaps with an interpolated segment.
size"sm" | "md" | "lg""md"Aspect ratio.
showGrid / showXAxis / showLegend / showTooltipbooleantrueToggle chart chrome.
showYAxis / showDotsbooleanfalseOff by default.
xAxisLabel / yAxisLabelstring—Axis titles.
xTickFormatter / yTickFormatter(value, index) => string—Format tick text.
startEndOnlybooleanfalseRender only the first and last category ticks.
dashedSeriesstring[][]Series keys rendered with a dashed stroke.
labelstring—Accessible name; renders the chart as a role="figure".
descriptionstring—Visually hidden summary for assistive tech.
selectionMode"none" | "single""none""single" lets a reader choose one period by click, tap, Enter or Space; choosing it again clears it.
selectedstring | null—The categoryKey value of the chosen period, controlled. null chooses nothing.
defaultSelectedstring | nullnullThe categoryKey value of the period chosen at first render, uncontrolled.
onSelectedChange(key, { datum, index, source }) => void—Called on every choice and clear; source is "pointer" or "keyboard".
activestring | null—The categoryKey value of the lit period, controlled: opens the tooltip on it.
onActiveChange(key: string | null) => void—Called when the chart's own pointer or arrow keys move to another period.
stringsPartial<AreaChartStrings>English, Arabic under dir="rtl"Selection's words per entry: selected, cleared, items, period.
childrenReactNode—Extra Recharts children — ReferenceLine, ReferenceArea, Brush.
dir"ltr" | "rtl"inheritedReading direction. Unset, read off the chart's position in the page once it mounts.
loadingbooleanfalseRender the skeleton.
errorReactNode—Render an error message instead of the chart.
emptyStateReactNode"No data to display"Shown when data is empty.
initialDimension / debounce—{320,200}Pre-measurement size and resize debounce, forwarded to Recharts.

Theming

Every colour resolves to a Tessina token — nothing is hardcoded:

ElementToken
Series fill / stroke--chart-1 … --chart-6 (via config[key].color)
Grid linesmuted-foreground at 20%
Axis tick labels + axis titlesmuted-foreground
Tooltip surfacepopover / popover-foreground / border

To re-skin a series, change the token reference in config (e.g. color: "var(--chart-3)") or override the --chart-N token in your theme.

Accessibility

VoiceOver + Safari: passed 2026-09-14. A static read gives "Desktop visitors peaked in February, figure" and the axis labels. Tab lands on the plot, which VoiceOver reads after the figure name as "web application", and the arrow keys read each point through the tooltip ("Feb, Desktop, 305"). NVDA and JAWS are untested.

  • Name the insight, not the axes. label renders the chart as a named role="figure"; description adds a visually hidden summary. A static read has to carry the message — interaction is additive, never required.
  • Keyboard. Recharts' accessibilityLayer is on by default: the chart surface is a tab stop, ←/→ step through data points, Enter pins the tooltip and Esc dismisses it. There is no wrapping and no Home/End. The focus ring is drawn by ChartContainer — Recharts ships none. See the Chart page for the full keyboard table and the VoiceOver QuickNav caveat.
  • Gaps are never interpolated. connectNulls is off by default: a missing value stays a gap rather than being bridged. Turn it on only when a gap genuinely means "unchanged".
  • Colour is never the only differentiator. Pair multi-series with dashedSeries, dots or direct labels, and keep to about five series — past that a stacked area stops being readable and a data table serves better.
  • With selectionMode="single" the periods become a list to choose from. The chart's one tab stop is a named listbox ("Traffic: Periods"), each period an option with aria-selected and a name that carries its readings, and the period the arrow keys are on is its aria-activedescendant. Enter or Space chooses that period, so Enter no longer toggles the tooltip; Escape still hides it. A polite status region says "Feb selected" or "Selection cleared" once per change. The screen reader pass of this mode is still to be run.
ChartBar Chart

On this page

When to useWhen not to useInstallationUsageExamplesDefaultMultiple SeriesStackedExpandedCurveAxesReference lines and bandsRange bandMissing dataNegative valuesSparklinesInteractiveChoosing a monthOn a coloured plateStatesAPI ReferencePropsThemingAccessibility