import { AutoChart } from "@elabs-ai/components-charts";npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-chartsPaste it into Claude Code, Cursor, Codex or any other coding agent. Text in [brackets] is yours to fill in.
Add the brand-ui AutoChart chart (from @elabs-ai/components-charts) to this project. 1. Read https://elabs-ai.com/llms.txt first: it maps every package and the rules. If you can use MCP servers, connect https://elabs-ai.com/mcp and use its search, docs and tokens tools. If not, run the same lookups in the terminal: `npx -y @elabs-ai/components-cli search "<what you need>"` and `npx -y @elabs-ai/components-cli docs <Component>`. 2. Look AutoChart up before writing code: `npx -y @elabs-ai/components-cli docs AutoChart` prints its real props, variants, what it pairs with and what to avoid. 3. If @elabs-ai/components-charts is not installed yet: `pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts` (or `npm install @elabs-ai/components-tokens @elabs-ai/components-ui @elabs-ai/components-charts`). If this is the first brand-ui package in the project, wire it once: import `@elabs-ai/components-tokens/styles.css` plus the `themes/light.css` and `themes/dark.css` stylesheets in the CSS entry, add one Tailwind `@source` line per installed @elabs-ai package (Tailwind does not scan node_modules, so without it everything renders unstyled), and wrap the app root in `ThemeProvider` from `@elabs-ai/components-tokens`. 4. Use it here: [the screen or file, and what it should show] 5. Rules: use only @elabs-ai/components-* components and the semantic tokens — no raw colours, no raw font sizes, no arbitrary Tailwind values. Look up each component's real props with the docs tool before you use it; never guess a prop. 6. Done means: the typecheck passes, `npx -y @elabs-ai/components-cli audit src --strict` reports nothing, and you have opened the app and looked at every screen you touched in the light and the dark theme.
Avoid
- Hand-picking a chart type when the spec already encodes the intent — AutoChart is the agent-facing entry point.
- Putting raw colors in a spec's series — the chart-1…chart-5 tokens are the palette in every theme.
- Passing an empty dataset with no not-ready signal — render the loading state instead of an empty frame.
Works with
Used inside
Pairs with
Examples
With Analytics
`spec.analytics` — the serialisable overlays an agent can ask for: here an average line, the 25–75 percentile band and a linear trend with its r² in the legend. No callbacks in a spec; `AutoChart` hands the list to the container unchanged.
Bar Grouped
Grouped bar chart with three regional series.
Bar Stacked
Stacked bar chart — same data, stacked mode.
Donut
Donut chart with a center hole.
Scatter
Scatter chart with numeric x (ad spend vs conversions).
Radar
Radar chart comparing two teams across five metrics.
Funnel
Funnel chart showing a conversion pipeline.
Currency Formatted
Currency-formatted y-axis via the `valueFormat` hint (line chart).
Copy Exact Value
Values are compacted on the axis and in the tooltip, so the exact figure has to stay reachable: `AutoChart` defaults `copyValueOnActivate` to `true`, which mounts the keyboard datapoint layer (real buttons OUTSIDE the aria-hidden `<svg>`) and a persistent polite live region for the "copied" announcement. Clicking or pressing Enter on a point copies its exact value.
Copy Exact Value Disabled
`copyValueOnActivate={false}` opts the tile out entirely — no datapoint layer, no live region, and the chart's DOM is what it was before the feature existed.
Unsupported Fallback
A type outside the `ChartType` union renders a `ChartFallback`. `sankey` is one of the four shapes AutoChart deliberately never infers or renders — a flat spec cannot express a node/link graph unambiguously, so it stays explicit-container-only. The panel speaks to the reader (“This chart can’t be displayed.”) and is a settled result, not a live region; the type name goes to a dev console warning instead (#304).
Empty Data
Empty data array renders a "No data to display" fallback.
Loading
Loading vs ready (#268) — a layout-shaped skeleton at the chart's normal height.
In Chat Conversation
InChatConversation — shows AutoChart embedded inside an AI tool-call output. Uses a minimal token-styled mock shell (plain divs) instead of the full `@elabs-ai/components-ai` Conversation/Message/Tool stack, keeping this story self-contained within the `@elabs-ai/components-charts` package (which does NOT depend on `@elabs-ai/components-ai`). The REAL composition with `@elabs-ai/components-ai`'s Conversation/Message/Tool/ToolOutput components lives in the copy-owned `ai-chart` registry block (`registry/blocks/ai-chart/`) — a registry block may import both siblings, whereas a package (and therefore a package's story) may not. See `research/ai-charts/01-ai-chart-integration-plan.md`.
Candlestick Inferred
OHLC columns on a date axis are candles, never a line.
Treemap Inferred
A nested hierarchy is the one shape only a treemap can read.
Treemap Palette
`palette` on a treemap spec (#306): colour is a DATA encoding here — `"categorical"` encodes the top-level group, `"sequential"` the leaf value, `"mono"` (the default) nothing. Everything else about the spec is unchanged.
Bump Inferred
Long `(period, entity, rank)` rows DECLARED as a ranking. Without the declaration the identical shape reads as a heatmap — the two cannot be told apart structurally, which is why the ranking rule runs first and asks for a signal.
Calendar Inferred
A year of dated rows is more days than a line can resolve.
Stream Inferred
Stacked bands over time read as a streamgraph, not as lines.
Heatmap Inferred
Two categorical keys and one measure make a matrix, whatever the row count.
Dumbbell Inferred
Two measures whose names read as before/after are one measure twice.
Histogram Inferred
A bare column of observations has no category to plot against.
Strip Inferred
Few enough records per group and every one can still be drawn.
Box Inferred
Past ~200 records a group, the summary reads better than the records.
Waterfall Inferred
A total/net/gross checkpoint row makes these deltas rather than categories — and it outranks the diverging rule, which this same data also satisfies.
Diverging Bar Inferred
A single measure that crosses zero: the baseline is the story.
Unit Inferred
The same shares that would draw a pie draw countable marks instead once the spec asks for the editorial register — `emphasis: "editorial"` is the only difference between this story and a pie.
Unit plotHeight forwarding (400px)
`AutoChart`'s own `plotHeight` prop, forwarded straight to `UnitChart`'s `plotHeight` (not the deprecated `height` alias) — a regression lock for G1 (RM-183 review round 2): a `ChartPlotBox` bug erased every resolved plot height on `layout="waffle"`/`"field"`, collapsing this to the 100px content floor regardless of the 400px asked for here.
Line Legend From Column Keys
A series known only by its column key (no `label`) is NOT end-labelled (RM-110), so the legend engine's default shows a legend — forwarded through `spec.legend` into `LineChart`'s own `legend` prop (`LEGEND_ENGINE_TYPES`), never a second, `AutoChart`-owned implementation. The rendered `.legend-container` is byte-identical to an explicit `<LineChart legend>` built from the same normalized series (see `auto-chart.test.tsx`'s "renders the identical legend DOM…" test, and `LineChart`'s own `LegendToggle` story for the equivalent explicit call).
Line Faceted Legend
`ChartSpec.facet` (RM-120) splits one line spec into a grid, one panel per `region` — and `legend: true` (RM-118) shows ONE shared `Chart legend` above the whole grid, not one per panel and not the old per-chart `AutoLegend` a faceted spec briefly lost across the wave-2 branch merge.
Bar Faceted Legend
RM-118 Part B × RM-120, sitting 2: `bar` joined `LEGEND_ENGINE_TYPES` this wave, so a faceted bar spec gets the same fix as `LineFacetedLegend` above — ONE shared `Chart legend` over the whole grid, never one per panel.
Pie Faceted Legend
RM-118 Part B × RM-120, sitting 2 (fix round 1, item 3): the pie half of `BarFacetedLegend` above — same ONE-shared-`Chart legend`-over-the-grid treatment, but the items must be the slice CATEGORIES (deduped across panels via `pieRows`, the same source the retired `<AutoLegend>` used), never the value column and never one legend per panel. This is the exact regression class the sitting-2 `legendItems`-not-`series` fix in `auto-chart.tsx` guards — see the matching unit tests in `auto-chart.test.tsx`'s "AutoChart faceted pie legend" block.
Dual Axis Spec
`type: "dual-axis"`: order counts as columns on the left scale, the conversion rate as a line on the right. `axes.y2.align: "ticks"` puts both scales on the same gridlines; the legend splits by side and the tooltip is a table with a header per axis.
Dual Axis Spec Without Line
A dual-axis spec with no line series cannot be drawn honestly: `ChartFallback` says so.
Choropleth Spec
`type: "choropleth"`: the rows join the bundled US-states map on their postal code, and a stepped quantile scale gives every class the same number of states. The map is fetched only when a spec names one, so a bar-chart spec never pays for it. At the narrow tier the colour key moves below the map and the place names step aside.
Choropleth Spec Without Map
A choropleth spec with no map cannot be drawn: `ChartFallback` says so.
API
AutoChart
| Prop | Type | Description |
|---|---|---|
specrequired | ChartSpec | The serializable chart specification produced by an LLM tool-call. `spec.type` is optional; omit it and the data shape decides (see `explainChartType`). The full `ChartType` union AutoChart renders is: `line` | `area` | `bar` | `pie` | `scatter` | `radar` | `funnel` | `candlestick` | `heatmap` | `calendar` | `waterfall` | `dumbbell` | `unit` | `treemap` | `histogram` | `box` | `strip` | `bump` | `stream` | `diverging-bar` | `dual-axis` | `choropleth`. Anything else — including `network`, `parallel`, `tree` and `sankey`, which stay explicit-container-only — renders `ChartFallback` instead. That list is not hand-kept prose: `auto-chart.test.tsx` parses it back out of this comment and asserts it equals `CHART_TYPES`, so a type added to the union without being documented here fails the suite. |
plotHeight | Responsive<ChartPlotHeight> | Height of the drawing area only; the title and legend stack around it. A number of pixels, `{ aspect }` (width / height), or a per-breakpoint `{ base, medium?, narrow? }`. Default: the chart family's own default (`{ aspect: 2 }` wide, `{ aspect: 1.25 }` narrow for the 2:1 families). |
height | number | @deprecated Use `plotHeight`. Removed in 7.0.0. Until then it is read as `plotHeight` and logs one development warning per page. |
loading | boolean | Loading vs ready — renders a layout-shaped skeleton at the normal chart height instead of resolving `spec`. Default: `false`. |
copyValueOnActivate | boolean | Copy a datapoint's EXACT value to the clipboard when it is activated by pointer or keyboard. Default **`true`** here, unlike the raw chart containers, which default it to `false`. The asymmetry is deliberate. `AutoChart` renders compact axis labels (`1.5M`) from a spec its caller never sees the axis config for, so without this there is no way to recover the exact figure. A raw container's caller owns the axis and can format it themselves, and turning this on mounts the datapoint interaction layer — which would break the documented guarantee that a chart with no interaction props renders byte-identical DOM. Set `false` to keep `AutoChart`'s pre-existing DOM (no interaction layer, no keyboard targets). |
selectionStates | ChartSelectionStatesResolver | Selection input (RM-073), forwarded to the chosen container. The resolver's `category` is read from `spec.fields.category` (default `spec.x`), so a host maps selection without knowing the chart type. |
dimExcluded | boolean | Dim `excluded` marks. Default `true`. Forwarded with `selectionStates`. |
hoverCategory | ChartHoverCategory | Shared-crosshair category from a sibling chart (RM-073). |
onHoverCategory | (category: ChartHoverCategory) => void | Fires with the hovered category on pointer move, `null` on leave (RM-073). |
onDatapointClick | ChartDatapointClickHandler | Forwarded to the chosen container's own `onDatapointClick` (RM-075), when that family accepts one (bar, line, area/stream, pie, waterfall, heatmap/calendar, dumbbell, unit, treemap, histogram/box/strip, bump, funnel, diverging-bar). Absent on scatter/radar/candlestick — those containers don't accept it yet. Unset by default, so the default render stays byte-identical (#349's own rule: "with it unset the chart renders exactly as before"). |
onSelectionIntent | ChartSelectionIntentHandler | Selection intents from the gestures `spec.selection.gestures` enables (RM-145, ADR 0040 §3) — on bar, line, area, scatter, heatmap and the distribution families. With `spec.selection` unset nothing mounts. |
Theming
The tokens each state resolves to. Change the token and every theme follows.
| State | Token |
|---|---|
| series | --chart-1 … --chart-5 |