TimeSeriesAreaChart
ImplementedTime-series area chart with gradient fill (recharts integration). Used for revenue-over-time with currency-formatted axes.
components/organisms/TimeSeriesAreaChart/TimeSeriesAreaChart.tsxSingle-series time-series area chart (recharts-based) with a vertical gradient fill, currency-ready axis/tooltip formatters and a designed empty state — pass hasData={false} plus emptyMessage instead of branching at the call site.
TimeSeriesAreaChart
Organism — Chart family
One Area over dataKey, stroked with color (default --ep-text-teal) and filled with a gradient keyed by gradientId. yAxisFormatter and tooltipFormatter adapt the public (number) => string contract; labelFormatter adapts (label: string) => string.
EmptyState
Organism — Chart family
hasData={false} + emptyMessage: the designed empty state renders inside the fixed-height container — no call-site branching, the frame stays stable.
Aucun revenu pour cette période
Loading
Organism — Chart family
loading: renders nothing inside the fixed-height container — height is preserved so the layout does not shift when data lands.
Usage
Feed day-keyed rows with one numeric dataKey, name the chart with ariaLabel, and pass the same money formatter to yAxisFormatter and tooltipFormatter (the AdminStatistics pattern). Pass a unique gradientId per instance when several area charts share a page — SVG ids are global.
import { TimeSeriesAreaChart } from '@epasslive/design-system'
const daily = [
{ day: '2026-08-31', revenue: 1240 },
{ day: '2026-09-01', revenue: 1810 },
{ day: '2026-09-02', revenue: 990 },
{ day: '2026-09-03', revenue: 2260 },
{ day: '2026-09-04', revenue: 3140 },
{ day: '2026-09-05', revenue: 2870 },
{ day: '2026-09-06', revenue: 1980 },
]
const fmtDay = (d: string) =>
new Date(d).toLocaleDateString('fr-CA', { month: 'short', day: 'numeric' })
const fmtMoney = (v: number) =>
v.toLocaleString('fr-CA', { style: 'currency', currency: 'CAD', maximumFractionDigits: 0 })
<TimeSeriesAreaChart
data={daily}
xAxisKey="day"
dataKey="revenue"
xAxisFormatter={fmtDay}
yAxisFormatter={fmtMoney}
tooltipFormatter={fmtMoney}
labelFormatter={fmtDay}
ariaLabel="Revenus quotidiens, du 31 août au 6 septembre"
gradientId="adminDailyGrad"
hasData={daily.length > 0}
emptyMessage={<p>Aucun revenu pour cette période</p>}
/>Conventions
The default color (var(--ep-text-teal)) meets the ≥4.5:1 non-text contrast minimum on both themes (5.45:1 light / 4.75:1 dark on --ep-surface-card, WCAG 1.4.11); override with another audited token, never a raw hex. Gate the render with hasData and carry the designed empty state in emptyMessage — the height is fixed so loading, empty and populated states never shift the layout. Animation is disabled (isAnimationActive={false}) — the chart renders instantly without transitions. The organism imports charts.css (shared with StackedBarChart) for recharts DOM styling — token-based, dark/light auto-flip. This organism is single-series by design; for multi-series stacked bars use StackedBarChart.
Accessibility
When !loading && hasData && ariaLabel, the wrapper is a role="img" region named by ariaLabel (WCAG 1.1.1 / 4.1.2) — always pass a summary of metric + period (e.g. "Revenus quotidiens, du 31 août au 6 septembre"); the recharts SVG exposes no per-point text alternative. The emptyMessage node renders in a plain div (no img role) so its text content stays exposed to screen readers, and loading renders nothing — the accessible name exists only on the chart branch; the empty and loading branches have no img role. Unlike Chart, there is no built-in sr-only data table — for exact values, pair with an adjacent table (e.g. AdminDataTable) or nearby prose.
Props
data*Record<string, unknown>[]Data rows — one per x-axis tick, keyed by xAxisKey plus the dataKey field.
xAxisKey*stringRow field rendered on the x-axis (the time label, e.g. 'day').
dataKey*stringRow field plotted on the y-axis (e.g. 'revenue').
colorstringvar(--ep-text-teal)Stroke and gradient color — pass a token, not a raw hex.
heightnumber280Chart height in pixels.
xAxisFormatter(value: string) => stringFormats x-axis ticks (e.g. ISO date → '12 août').
yAxisFormatter(value: number) => stringFormats y-axis ticks (e.g. money).
tooltipFormatter(value: number) => stringFormats the tooltip value (e.g. money).
labelFormatter(label: string) => stringFormats the tooltip header label (e.g. ISO date → short date).
ariaLabelstringAccessible label for the chart region — produces a role="img" wrapper only when !loading && hasData && ariaLabel; otherwise dropped. Summarize the metric and period.
loadingbooleanRenders nothing inside the fixed-height container while data is fetched.
gradientIdstringtsAreaGradSVG gradient id — pass a unique id when rendering several instances on one page.
emptyMessageReact.ReactNodeRendered instead of the chart when hasData is false (e.g. a muted Body empty-state).
hasDatabooleanGate for the empty state — render the chart only when truthy.
Used By
storefront/src/components/dashboard/admin/AdminStatistics.tsx— daily-revenue area chart with money-formatted axes
Props
TimeSeriesAreaChart
dataRecord<string, unknown>[]—Array of data points
xAxisKeystring—Key for the x-axis values
dataKeystring—Key for the y-axis data values
colorstringvar(--ep-text-teal)Stroke and gradient color (WCAG-safe on card surface)
heightnumber280Chart height in pixels
ariaLabelstring—Accessible label for the chart region
loadingboolean—Renders nothing while fetching
gradientIdstringtsAreaGradSVG gradient id — unique per instance
emptyMessageReactNode—Rendered when hasData is false
hasDataboolean—Gate for the empty state
<TimeSeriesAreaChart />Accessibility
ARIA
1 ruleUsage
Import
import { TimeSeriesAreaChart } from "@epasslive/design-system"Example 1
<TimeSeriesAreaChart data={daily} xAxisKey="day" dataKey="revenue" hasData />