Area chart
NewThe range chart: one figure over time as a single Orbit line over a wash that fades to nothing, with an optional dashed comparison and a readout that snaps to the nearest day. Reach for it under headline figures, for takings, orders or visits across a range.
Basics
Give it one point per day, oldest first, with dates as YYYY-MM-DD strings (read as local dates) or Date objects. Hover the chart, or tab to it and use the arrow keys, to read each day.
With a comparison
Add compare to each point and the chart draws the earlier period as a dashed grey line, adds a legend above the plot, and shows both values and the change in the readout. Name both series for what they are with valueLabel and compareLabel.
Ranges and refreshes
A new range (different days) redraws: the old line fades out as the new one is uncovered from the left. A refresh of the same range (same days, new figures) morphs the line, the wash and the gridlines in place, so you can see what changed. Switch the range, then press Refresh.
The readout
The crosshair snaps to the nearest day and the readout glides after it on a spring, opening on whichever side has room. It leads with the value in Sora, keys each series with a short stroke that matches its line, and shows the change against the comparison. Here it is held open on one day in both themes.
Axes and formatting
Four formatters shape every label. The defaults are UK formats: dates such as "3 Aug" on the axis, "Mon 3 Aug" in the readout, and compact values such as "2.5k" on the gridlines. For hourly data, pass dates for each hour and format them as times ("14:00").
| Prop | Formats | Default |
|---|---|---|
formatDate | Dates under the plot | "3 Aug": day and short month, en-GB |
formatTooltipDate | The date heading the readout | "Mon 3 Aug": weekday, day and short month |
formatTick | Gridline labels | "2.5k": a compact number |
formatValue | Values in the readout and the accessible summary | "2,512.4": a grouped number |
How many labels
Dates are spaced to fit, roughly one per 84px, counted back from the latest day so today always has a label. The first and last labels align to the edges of the plot. Gridlines fall on round values (steps of 1, 2, 2.5 or 5) and always include zero.
Loading and empty
With loading and no data yet, a soft silhouette of a chart shimmers where the plot will be. With loading and data already drawn, the chart holds its frame at half strength until the new data lands. With no data, emptyMessage sits in the middle of the plot.
Motion
| Moment | What happens |
|---|---|
| Arrival | The line is uncovered left to right behind a soft edge over 720ms, and the wash settles in after it. |
| A new range | The old line fades out over 220ms while the new one is uncovered. |
| A refresh | The line, wash and comparison morph to their new shape over 720ms, and gridlines and their labels glide with them. |
| Reading | The crosshair, markers and readout glide from day to day on the snappy spring. |
| Reduced motion | The line fades in, refreshes swap without morphing, the readout jumps, and the loading silhouette breathes instead of shimmering. |
Guidelines
- One figure at a time. To offer several, put them in Figure tabs above the chart and let it follow the one that is selected.
- Choose the range with a Segmented control above the chart, and compare with the period just before it, of the same length, unless the page says otherwise.
- Name the comparison for what it is: "Previous 30 days" or "Same days last year", never just "Before".
- Give it room: 240px (the default) on a page, 200px at the least. The height includes the date labels; the legend sits above.
Accessibility
- The plot is an image with a summary for its name, generated from the data unless you pass
label: the range, the highest and lowest days, and the comparison. - Tab to the plot and it reads the latest day. Left and right arrows step through the days, Home and End jump to the ends, and Escape hides the readout. Each step is announced politely.
- The focus ring is teal, 2px, and sits 6px outside the plot.
- While
loading, the plot is marked busy. The readout itself is hidden from assistive tech, because the announcement already says what it shows. - Every movement respects reduced motion (see Motion).
Props
Also accepts every native div attribute except children.
| Prop | Type | Default | Description |
|---|---|---|---|
dataRequired | readonly AreaChartDatum[] | None | One point per day (or bucket), oldest first. |
height | number | 240 | Height in px of the plot and its date labels. The legend sits above. |
valueLabel | string | 'This period' | Names the main series in the legend and the summary. |
compareLabel | string | 'Previous period' | Names the comparison series. |
formatValue | (value: number) => string | grouped number | Values in the readout and the summary. |
formatTick | (value: number) => string | compact number | Gridline labels, e.g. "2.5k". |
formatDate | (date: Date) => string | day and month | Dates under the plot, e.g. "3 Aug". |
formatTooltipDate | (date: Date) => string | weekday, day and month | The date heading the readout. |
loading | boolean | false | A shimmering silhouette with no data; a dimmed, held frame with data. |
emptyMessage | ReactNode | 'Nothing to show for this period yet' | Shown in the plot when data is empty. |
label | string | None | Accessible summary. Generated from the data when omitted. |
AreaChartDatum
| Prop | Type | Default | Description |
|---|---|---|---|
dateRequired | string | Date | None | The day or bucket. YYYY-MM-DD strings are read as local dates. |
valueRequired | number | None | The figure for that day. |
compare | number | null | None | The same point in the comparison period, drawn dashed. |