Chart
Token-themed chart primitives (container, config, tooltip, legend, data-table) composed with Recharts.
@garn/ui/chartDefault
Area chart with accessible name, gradient fills, tooltip, legend + a ChartDataTable.
Show data table
| Month | Revenue | Profit |
|---|---|---|
| Jan | $4,200 | $1,800 |
| Feb | $5,100 | $2,100 |
| Mar | $4,800 | $1,950 |
| Apr | $6,200 | $2,600 |
| May | $7,100 | $3,100 |
| Jun | $6,800 | $2,900 |
Bar
Stacked bars with rounded tops.
Line
Multi-series line with active dots.
Pie
Donut with a token-tinted slice palette.
Interactive Legend
Click the legend to toggle series (useChartVisibility).
Reference Line
A dashed target line via ChartReferenceLine.
States
Loading (ChartSkeleton) + empty (Empty).
Loading
No data
Metrics appear once data starts flowing.
Formatting
Intl date/compact-currency axes + data labels.
Combo
Dual-axis composed bar + line.
Scatter
Two numeric axes; correlation.
Radar
Multi-axis comparison of two series.
Radial Bar
Concentric progress rings.
Funnel
Conversion funnel with stage labels.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add chart- Registry
chart- Source
- chart.tsx
- Deps
recharts- Registry deps
utilsuse-prefers-reduced-motionskeleton
Import
import { Chart } from "@garn/ui/chart";Props
Generated from the component's TypeScript types.
animate- Description
- Entrance/update animation for the series inside. The container defaults `isAnimationActive` onto the library's series (and tooltip) so animation turns off automatically under `prefers-reduced-motion`; set `false` to force a static chart (screenshots, print). A series' own explicit `isAnimationActive` always wins over this default.
- Type
boolean
childrenRequired- Description
- A single Recharts chart element (e.g. `<LineChart>…</LineChart>`).
- Type
React.ReactNode
configRequired- Description
- Series-key → label + token color map. Drives tooltip/legend + `--color-*`.
- Type
ChartConfig
Plus 279 inherited native <div> attributes.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="chart"]Overview
Chart is not one chart — it's the themed primitives every chart is built from: a ChartContainer that turns a typed ChartConfig into scoped --color-<series> tokens and token-styles the SVG, plus a garn-styled tooltip, legend, data-table, reference lines, gradients, and loading/empty states. You compose these with the underlying library's chart elements; each chart type — line, area, bar, pie, scatter, radar, radial, combo, funnel — is a recipe, not a bespoke component. Recharts is the engine, added only when you copy a chart in (the sparkline and gauge stay engine-free).
Guidelines
Compose, don't configure. garn ships primitives + recipes, not a <LineChart data={} /> engine — you write the chart body in JSX and keep full control (mirrors the table decision). Copy a recipe and swap the data.
Theme through config. Point each series' color at a --garn-chart-* token; the container injects var(--color-<series>), so dark mode and re-theming come for free. Never hardcode a hex.
Own the accessibility. A chart needs an accessible name and a text/data-table equivalent (ChartDataTable gives you one for free), plus accessibilityLayer for keyboard + tooltip-on-focus. Distinguish series with more than colour.
Format for humans. Use numberFormatter/dateFormatter for axis ticks and tooltips, and a per-series config.formatter so values read as currency/percent/dates.
Let the container own motion. The entrance animation is JS-driven, so CSS motion-reduce can't stop it — ChartContainer does: it defaults isAnimationActive onto the series and turns animation off under prefers-reduced-motion. Set animate={false} for a static chart (screenshots, print, visual-regression suites); a per-series isAnimationActive overrides the default either way, and custom series read useChart().animate.
Best practices
- Drive series colours from
config→var(--color-<series>); enableaccessibilityLayer. - Pair every chart with an accessible name +
ChartDataTable.
- Don't hardcode colours or reach past the primitives into raw library styling.
- Don't ship a chart with no accessible name or data-table equivalent.
- Don't hand-wire
isAnimationActiveper series just to respect reduced motion — the container already does; reserve the per-series prop for real exceptions (e.g. the polar 0×0 gotcha).
Accessibility
- • Give the chart an accessible name (a `<figcaption>` + `aria-labelledby`, or `aria-label`).
- • Provide a text/data-table equivalent — `ChartDataTable` generates one from the same config + data.
- • Enable the library's `accessibilityLayer` for a single tab stop + arrow-key point navigation + tooltip-on-focus.
- • Distinguish series without colour alone (markers / dashes / direct labels); series colours meet ≥3:1 in both themes.
- • Series entrance animation is disabled automatically under `prefers-reduced-motion` (the container defaults `isAnimationActive` onto its series) — don't re-enable it per-series without cause.
- Status
- Stable
- Version
v0.3.0- Introduced
v0.2.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.