import { BarChart } 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 BarChart 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 BarChart up before writing code: `npx -y @elabs-ai/components-cli docs BarChart` 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.
Use it for
- How do these compare? A few categories, compared.
- categorical comparison of one or more measures across a small set of named categories
- a single signed measure around a meaningful zero, as diverging bars with a zero line
Avoid
- a time axis with many points — use a line or area chart
- Truncating the value axis so small differences look large — a bar axis starts at zero.
- Hardcoding series colors — use the chart-1…chart-5 tokens so every theme works.
- Rendering an empty frame before data arrives — use the shipped chart skeleton utilities.
Works with
Contains
Used inside
Examples
Mini Chart 120
120 categories with the mini chart. The plot shows as many categories as a readable band allows; drag the window (or click the strip, or wheel over it) to scroll. The value axis stays put — it is the full data's.
Auto Twenty Items
`scrollbar="auto"` with `maxVisibleItems={20}`: the strip appears because 120 > 20, and the plot shows exactly 20 bars. `onDatapointClick` on a visible bar reports the row's index into the FULL `data`.
Keyboard Handles
Keyboard: Tab to the window's start handle; ArrowRight ×3 moves the start three categories on, Home returns it to the first one. The first category label follows every step, and the live region restates the rows.
Horizontal Rows 80
Horizontal bars, 80 rows: the strip is VERTICAL, on the right edge; its shadow is the bar lengths condensed. Handles announce "Row n of N"; ArrowDown moves a handle down.
Stacked Stable Axis
Stacked bars scrolled with a stable value axis: the outlier at C084 sets the axis for the whole data, so the first window's short stacks read against the same scale they will have everywhere else.
Visible Domain Refit
`windowDomain="visible"` refits the value axis to the window (still zero- based — bars are lengths). Scroll to C084 and the axis grows to hold it.
Composed Category
A composed chart in category mode (`xScale="band"`): bars and a line scroll together.
Heatmap 365 Days
A heatmap with 365 day-columns scrolls by COLUMN: the ramp stays the full year's (`windowDomain="all"`), so a shade means the same count everywhere.
Plain Bar
`scrollbar="bar"`: a plain scrollbar strip — the window only, no shadow.
Align End
`align="end"`: the first window sits on the LATEST categories.
Narrow Tier
The narrow tier (< 480 px): the strip is 32 px thick and `maxVisibleItems` takes a per-tier value — 20 wide, 8 narrow.
API
BarChart
| Prop | Type | Description |
|---|---|---|
datarequired | Record<string, unknown>[] | Data array - each item should have an x-axis key and numeric values |
xDataKey | string | Key in data for the categorical axis. Default: "name" |
margin | number | Partial<Margin> | Chart margins: one number for every side, or per side. Default: 40 on every side. |
animationDuration | number | Animation duration in milliseconds. Default: 1100 |
animationEasing | string | CSS easing for bar grow transitions. |
enterTransition | Transition | Motion enter transition (spring or cubic-bezier tween). |
revealSignature | string | Signature of motion URL state — triggers enter replay when it changes. |
revealOn | ChartRevealOn | When the enter reveal is allowed to play (#175). `"mount"` (default) plays as soon as the chart renders — no change from today. `"inView"` holds the bars at their pre-enter state until this chart's own container scrolls to 30% visible. |
replayOnClick | boolean | Clicking the chart body replays the enter reveal (#175). Default `false`. |
aspectRatio | string | Aspect ratio as "width / height". Default: "2 / 1" |
plotHeight | Responsive<ChartPlotHeight> | The plot's own height (ADR 0039): px, or `{ aspect }` (width ÷ height), optionally per breakpoint. Wins over `aspectRatio`, which stays an alias. |
className | string | Additional class name for the container |
status | ChartStatus | Loading vs ready — shows skeleton chrome + placeholder bars while `"loading"`. Default: `"ready"`. |
loadingLabel | string | Centered shimmer label while loading. |
barGap | number | Gap between bar groups as a fraction of band width (0-1). Default: 0.2 |
barWidth | number | Fixed bar width in pixels. If not set, bars auto-size to fill the band. |
orientation | BarOrientation | Bar chart orientation. Default: "vertical" |
stacked | BarStacked | Stack bars instead of grouping them. `true` stacks raw values; `"percent"` normalises each category to 100 % (value axis 0–100 %, a `YAxis` without its own format prints percent, `labels` prints shares); `"diverging"` centres `divergingCenter` on the zero line with the series declared before it growing left/down and those after it right/up (Likert rows). Default: false |
stackGap | number | Gap between stacked bar segments in pixels, in every `stacked` mode. It is cut out of the boundaries between segments only, half from each side, so every stack still starts on the baseline and ends at its total. A `Bar`'s own `stackGap` overrides it for that series. Default: 0 |
divergingCenter | string | `stacked="diverging"`: the series straddling zero (e.g. `"Neutral"`). Unset: the series split in half. |
stackOrder | BarStackOrder | Segment order inside each stack (`stacked`/`"percent"`). Default: `"data"` (declaration order). |
showTotals | boolean | Print each stack's total just past its end. Default: false |
sort | BarSort | Row order: by value (`"asc"`/`"desc"`, the stack total when stacked) or `{ by, dir }`. Default: `"none"`. |
reverse | boolean | Reverse the (sorted) row order. Default: false |
groupBy | string | Gather rows by this column: horizontal bars get a bold header row per group, vertical columns a header above each group; groups are separated by a hairline and keep their own (sorted) order. |
colorBy | ChartColorBy | Colour each bar by another column through `resolvePalette` (six hues, then the neutral ladder with a dev warning) and show a colour key. One key per chart (RM-118 R4): whenever this produces a non-empty colour key, the `legend` container legend below YIELDS and renders nothing — `colorBy`'s own key already covers the same job, and `interactive: "toggle"` has no effect in that mode (there is no container legend to press). |
track | boolean | { fill?: string } | Paint a track behind each bar to the axis maximum ("to 100 %"). `true` uses `--chart-mono-2`, a mark-weight grey; `{ fill }` names another ink — a surface tone such as `var(--chart-segment-background)` when the track should read as paper, not as data. Default: false |
overlays | BarOverlay[] | Value markers and range spans drawn per bar on top of the series; listed in `legendItems`. |
comparison | BarComparison | A muted prior-period column behind each main column (the main column narrows to make room). |
comparisonLabel | BarComparisonLabel | Grey label beside each comparison pair. Default: `"none"`. |
childrenrequired | ReactNode | Child components (Bar, Grid, ChartTooltip, etc.) |
onPhaseChange | (phase: ChartPhase) => void | Reports reveal lifecycle for OG screenshots and loading orchestration. |
onDatapointClick | ChartDatapointClickHandler | Drill-down (#349). Fires when a bar is activated by pointer OR keyboard. Setting it mounts a keyboard-operable target layer OUTSIDE the aria-hidden SVG — one tab stop, arrow keys to traverse. Unset changes nothing. |
copyValueOnActivate | boolean | Put the datapoint's exact value on the clipboard when it is activated — the recovery path for a compact axis label. Default `false`; a chart with no interaction props still renders byte-identical DOM. A consumer-supplied `onDatapointClick` always wins. |
datapointLabel | ChartDatapointLabel | Override the accessible name of each keyboard drill-down target (#349). |
maxInteractiveDatapoints | number | Dev-warning threshold on the number of keyboard targets. Default 500 (#349). |
accessibleLabel | ChartA11yProps["accessibleLabel"] | Accessible name for the chart region (announces to AT on focus). |
accessibleDescription | ChartA11yProps["accessibleDescription"] | Supplemental description read by AT (e.g. series names + value range). |
palette | ChartPalette | Default fill for `Bar` children that don't set their own `fill`, via `resolvePalette` (RM-018) over the series count — so, for example, nine unfilled `Bar` series degrade to the neutral ladder with a dev warning instead of nine bars painted identically. A `Bar` with an explicit `fill` is never touched. Default: `"categorical"` (`resolvePalette`'s own default) — but see `applyBarPalette`: it only ever assigns colours to SERIES THAT WOULD OTHERWISE COLLIDE (2+ unfilled `Bar` children), so a chart with a single unfilled `Bar` keeps today's `--chart-line-primary`. |
legend | ContainerLegendProp | Legend engine (RM-118): `true` or a config object mounts `ChartLegend` beside the plot via `useContainerLegend`; `{ interactive: "toggle" }` turns each item into a real `aria-pressed` button that hides a series on grouped OR stacked bars — the value domain (`resolveBarValueDomain`, always zero-based) recomputes from the VISIBLE series only, and the hidden series' `<Bar>` never mounts, so it drops out of the datapoint layer too. `interactive: "hover"` (default) dims the other series via the existing `ChartLegendHoverProvider` seam `Bar` already reads. Unset renders NOTHING new (R1). Yields to `colorBy`'s own key — see its doc (R4, one key per chart). `{ values: true }` prints each series' total over every row (the `comparison` column's too; overlays show none), in the value axis' format (plain numbers for a percent stack, or when the series sit on value axes that format differently). |
scrollbar | ChartCategoryNavigatorProps["scrollbar"] | Overview strip style. Default `"none"`. `"miniChart"` / `"bar"` / `"auto"` mount it once the categories overflow `maxVisibleItems`. |
annotations | readonly ChartAnnotation[] | Declarative annotations in data units: text notes, ranges, reference lines, row notes. |
analytics | readonly ChartAnalytic[] | Statistical overlays computed from `data` (ADR 0040 §1): computed `line`/`band`s (average, median, percentile, std-dev, CI) drawn through the annotation layer, and `trend`/`window`/`forecast`/`errorBars` drawn as derived series with a legend entry, a tooltip row and an accessible sentence. Unset: no change. |
tooltip | boolean | Show a hover/focus tooltip. Default `true`: with no `<ChartTooltip>` child the chart adds a default one; a `<ChartTooltip>` child (for `variant`, `rows`, `content`, …) replaces it. `false` turns the default off. |
selectionStates | ChartSelectionStatesResolver<Record<string, unknown>> | Maps a mark (category, optional series key, optional raw row) to its selection state. Unset → the chart renders exactly as before. |
dimExcluded | boolean | Dim `excluded` marks and add their non-hue channel (the dashed frame). Default `true`; `false` keeps the `data-selection` attribute (so a host can style it) but paints nothing. |
selectionGestures | readonly ChartSelectionGesture[] | Gestures to enable. Unset → no gesture layer, DOM byte-identical to today. |
onSelectionIntent | ChartSelectionIntentHandler<Record<string, unknown>> | Fires with every intent. Required for the gesture layer to mount. |
selectionConfirm | ChartSelectionConfirm | Default `"immediate"`. |
selectionField | string | The field name carried in intents. Default: the chart's `xDataKey`. |
selectionHitRule | ChartSelectionHitRule | Rect / lasso hit rule. Default `"overlap"` (the report-builder BI suite). |
selectionToolbar | "auto" | "none" | `"auto"` (default): a toolbar appears when gestures are enabled; `"none"` hides it. |
window | NavigatorWindow | null | Controlled window. |
defaultWindow | NavigatorWindow | Initial window for the uncontrolled case. |
onWindowChange | (window: NavigatorWindow | null, meta: NavigatorChangeMeta) => void | |
minSpan | number | Smallest window the user can make: a duration in ms (time) or a row count (index). Default: 5× the median step (time; the stock-chart library' rule) / 3 (index). |
align | "start" | "end" | Where an automatic first window sits. `"end"` = the latest data (the associative BI suite `scrollStartPos: 1`). Default `"start"`. |
maxVisibleItems | Responsive<number | "auto"> | Category families (RM-141): how many categories the plot shows at once (the associative BI suite "Number of bars"). Default `"auto"` — as many as keep a readable band (`maxReadableCategories`); with `scrollbar="auto"` the strip appears only once the categories overflow that count. |
windowDomain | "all" | "visible" | Category families: `"all"` (default) keeps the value axis on the FULL data's domain while scrolling; `"visible"` refits it to the window. |
zoom | boolean | Pinch-to-zoom along the x axis (time x): two fingers on a touch screen, a trackpad pinch, or Ctrl/⌘ + wheel narrow the same window the strip moves; a two-finger drag pans it. `+` / `−` / `0` on the focused chart and the zoom buttons that appear once zoomed do the same from the keyboard. No strip is needed; with one, it follows. Default `true`; `false` leaves the gestures to the page. Off while the caller drives `xDomain` itself. |
Bar
| Prop | Type | Description |
|---|---|---|
dataKeyrequired | string | Key in data to use for y values |
name | string | Series display name: legend and tooltip text. Unset falls back to `dataKey`, same as `Line`/`Area`'s `name`. |
yAxisId | string | number | Y-scale group id for vertical bars (Recharts `yAxisId`). Default: `"left"`. |
fill | string | Fill color for the bar. Can be a color, gradient url, or pattern url. Default: var(--chart-line-primary) |
stroke | string | Color for tooltip dot. Use when fill is a gradient/pattern. Default: uses fill value |
fillStyle | SeriesFillStyle | How the bar is painted. `"solid"` (default) is the flat series fill — today's behaviour. `"hatch"` draws the series as an OUTLINED hairline hatch in its own colour, at any decoration level: the quiet voice next to a solid lead (a comparison, a projection, last year). `fill` must be a colour; a `url()` fill is left as authored. A per-row colour (`colorBy`, `highlightKey`) still wins and paints solid. |
lineCap | BarLineCap | Line cap style for bar ends: "round", "butt", or a number for custom radius. Default: "round" |
animate | boolean | Whether to animate the bars. Default: true |
animationType | BarAnimationType | Animation type: "grow" (height) or "fade" (opacity + blur). Default: "grow" |
fadedOpacity | number | Opacity when not hovered (when another bar is hovered). Default: 0.3 |
staggerDelay | number | Stagger delay between bars in seconds. Auto-calculated if not provided. |
stackGap | number | Gap between this series' stacked segments and their neighbours, in pixels. Each boundary between two segments loses half of it from this side; the stack's baseline and total never move. Default: the parent `BarChart`'s `stackGap` (0). |
groupGap | number | Gap between grouped bars in pixels. Default: 4 |
showValues | BarShowValues | @deprecated Use `labels` — the same values (ADR 0042 A.3, row 12). Read until 7.0.0, with one development warning; when both are set, `labels` wins. |
labels | BarShowValues | Print each bar's value as a `HaloText` label (the `text-chart-value` role, 800-weight — lieflat G3 Chunky Bars). `true`/`"outside"` place it just past the bar's far end; `"inside"` places it just inside. A negative bar's label is signed with a "−" (U+2212, not a hyphen) glyph. A bar narrower than `MIN_LABEL_BAR_WIDTH` hides its label rather than shrinking below `text-meta`. Default: off. A {@link BarShowValuesSpec} (RM-110) adds `"auto"` placement, hover-only visibility and an explicit `show` on/off. The object form's `placement` defaults to `"auto"` (inside when the label fits, else outside) — so `{ show: true }` is NOT the same as `true`, which always places the label outside. In a stack drawn from a layout (percent, diverging, ordered or totalled — RM-113) each segment centres its label whatever the placement, a percent segment prints its share, and a segment shorter than 24 px along the value axis stays unlabelled. |
valueFormat | ChartValueFormat | How `labels` prints this series' numbers — a preset or a spec (`{ suffix: " %" }`, `{ style: "currency", abbreviate: true }`, `{ sign: "always" }`). One notation for the whole series, as without it. Unset: today's locale number. A percent stack still prints shares. |
unit | number | Draw each bar as a countable `UnitStack` of `floor(value / unit)` rungs (vertical bars, `kind="rung"`) or ticks (horizontal bars, `kind="tick"`) instead of a solid fill — lieflat F1 Rung Bars. The rung pitch is derived from the value scale, not the bar's own pixel span, so one rung is worth the same amount in every column and the ladder never counts past the bar's own value (#241) — a value that is not an exact multiple of `unit` draws an honest partial. Width and opacity jitter via `seededRnd`, keyed per bar so neighbours never jitter in lockstep; every 5th unit draws heavier so the stack stays countable. Renders instantly (no `animate`/`animationType` grow-in). Default: off (solid fill). |
highlightKey | BarHighlightKey | Mark ONE bar as this series' "hero": it draws in `--chart-foreground` ink while every OTHER bar draws from `palette` instead of `fill` — lieflat's one-hero-bar-in-ink convention. A string/number is matched against the bar's category value; a function receives `(datum, index)`. Default: off (every bar draws `fill`). |
palette | ChartPalette | Palette the non-hero bars draw from when `highlightKey` is set, via `resolvePalette` (RM-018). Default: `"categorical"`. |
zeroLine | boolean | Draw a 0.8px `--chart-foreground-muted` hairline at the zero baseline across the whole plot. Default: auto — shown whenever ANY bar series in this chart has a negative value; pass `false` to force it off on this series, or `true` to force it on even with all-positive data. |
BarValueAxis
| Prop | Type | Description |
|---|---|---|
position | "top" | "bottom" | Where the tick labels sit. Default: `"bottom"`. |
tickCount | AxisTickCount | Tick target (RM-192, ADR 0042 A.2, row 8). `"auto"` (default) is this axis' own default: 3 ticks below 320 px of plot width, 5 above. |
numTicks | number | @deprecated Use `tickCount` — `numTicks` still wins when both are set, exactly as before. Read until 7.0.0, with one development warning. |
valueFormat | ChartValueFormat | How the tick values print — a preset or a spec (`{ suffix: " h" }`). Default: `"compact"`. |
title | string | A short name for the axis, printed after the last tick ("hours"). |
BarXAxis
| Prop | Type | Description |
|---|---|---|
tickerHalfWidth | number | Width of the date ticker box for fade calculation. Default: 50 |
showAllLabels | boolean | Keep every category (never stride over labels). Default: false. NOTE this no longer forces HORIZONTAL rendering: with dropping disabled the axis may still tilt, ellipsize, or hide itself when the labels cannot fit. |
maxLabels | number | Maximum number of labels to show. Default: 12 |
fit | CategoryAxisFit | How labels that do not fit their band are rescued (RM-108): - `"auto"` (default) — horizontal → two-line `wrap` → 45° tilt → ellipsis → stride → hidden; - `"wrap"` — the same cascade without the tilt rung (never rotates); - `"tilt"` — the pre-RM-108 cascade (skips `wrap`); - `"off"` — pins the pre-fit behaviour: full labels, count-capped stride, no measurement and no reserved axis space. The regression escape hatch. |
title | ReactNode | Axis title — names what the categories are (RM-188; the same part `XAxis` draws). |
titlePlacement | AxisTitlePlacement | `"outside"` (default): the title sits under the labels, flush with the plot's end edge. `"inside"`: hung inside the plot's bottom-end corner — the same fixed corner `XAxis` uses. By design it does not step around marks, so on a vertical bar chart it paints over the LAST bar (its halo keeps it legible); use `"outside"` when that bar must stay clear. |
BarYAxis
| Prop | Type | Description |
|---|---|---|
showAllLabels | boolean | Keep every category (never stride over labels). Default: true. NOTE this no longer implies every label renders in full: the axis still ellipsizes to the gutter it has, and hides itself when nothing legible fits. |
maxLabels | number | Maximum number of labels to show. Default: 20 |
fit | CategoryAxisFit | `"off"` pins the pre-fit behaviour — full labels, count-capped stride, no measurement and no reserved gutter. The regression escape hatch. Default: `"auto"`. |
maxWidth | number | The widest the label gutter may grow, in px. The gutter is measured from the labels and capped so a long name cannot eat the plot; the default cap suits one or two words. Raise it for rows whose names ARE the content — "Send Invoice → Payment Reminder" — and the chart still keeps its own minimum plot width. Default: 112. |
title | ReactNode | Axis title — names what the rows are (RM-188; the same part `YAxis` draws). |
titlePlacement | AxisTitlePlacement | `"outside"` (default): the title sits above the top row label, in the label gutter. `"inside"`: hung inside the plot's top-start corner — the same fixed corner `YAxis` uses. By design it does not step around marks, so on a horizontal bar chart it paints over the FIRST bar (its halo keeps it legible); use `"outside"` when that bar must stay clear. |
ChartTooltip
| Prop | Type | Description |
|---|---|---|
showDatePill | boolean | Whether to show the date pill under the plot. Default: shown when it fits the chart's bottom margin (≥ 36px) — never painted over a small plot. |
showCrosshair | boolean | Whether to show the vertical crosshair line. Default: true |
showDots | boolean | Whether to show dots on the lines. Default: true |
indicatorColor | string | ((point: Record<string, unknown>) => string) | Color for the crosshair/indicator line. When a function, receives the hovered point (e.g. for candlestick: match candle color from close vs open). Default: --chart-crosshair. |
content | (props: { point: Record<string, unknown>; index: number }) => React.ReactNode | Custom content renderer for the tooltip box |
rows | (point: Record<string, unknown>) => TooltipRow[] | Custom row renderer - return array of TooltipRow |
variant | ChartTooltipVariant | Box layout preset (RM-119). `"rows"` (default) is today's stacked `ChartTooltipContent`. `"table"` renders `ChartTooltipTable` — one column per series with a header row, the date in the `<caption>` (Datawrapper's dual-axis / multi-series shape, `dw-charts.md` §2.22). `"inline"` renders no box at all — `ChartTooltipInline` paints the hovered (or `focus`-nearest) series' value directly at the mark with `HaloText` (the bikes chart). Ignored when `content` is set — a custom renderer already owns the whole box. |
focus | boolean | Drive RM-112's per-series dim (`SeriesHoverDim`) from the tooltip's OWN nearest-series resolution: whichever series' y position is closest to the pointer, at ANY x along the crosshair, counts as hovered — not only a direct hover on that series' own 2px stroke. Works standalone: it registers "focus requested" on the shared series-mode context, so the dim fires with no `focusOnHover` prop on the `LineChart`/`AreaChart` container (a container `focusOnHover` still works exactly as before, and the two compose — either one turns the dim on). Also the default target series for `variant="inline"`. Default false. |
pin | boolean | Tap-to-pin (RM-119): on a coarse pointer, a tap keeps the tooltip open instead of clearing the instant the finger lifts. A second tap on the mark, `Esc`, or a tap outside the chart releases it (announced once via `role="status" aria-live="polite"`). Default: `true` only when the pointer is coarse (`(pointer: coarse)` media query); pass an explicit boolean to force either way regardless of pointer type. |
valueInTitle | boolean | Swap the tooltip box's own title for nothing — the hovered value moves to the chart's OWN title instead (RM-119, #610). Inside a `ChartFrame` that shows a title this is automatic: while a row is hovered, pinned or keyboard-focused the frame's title reads "Apr: Revenue 40" and is announced once through the frame's polite status; leaving restores the title. No wiring. Outside a frame (or in `chrome="bare"`, a custom `headerSlot`, the expanded dialog) only the box title is dropped — the date/category is still on `useChart().tooltipData` for a custom title. Default false. |
dotColor | string | ((point: Record<string, unknown>, line: LineConfig) => string) | Override tooltip dot fill. When omitted and `rows` is set, dot colors match row colors. When a function, receives the hovered point and line config. |
children | React.ReactNode | Additional content to show below rows (e.g., markers) |
className | string | Custom class name |
springConfig | SpringConfig | Per-chart override for the crosshair / dot / date-pill spring. |
boxSpringConfig | SpringConfig | Per-chart override for the floating-panel spring. |
panelStyle | React.CSSProperties | Inline styles for the tooltip panel (background, blur, etc.). |
unit | string | Unit text appended to every DEFAULT row's value (RM-109) — the same `unit` `<YAxis>` paints on one tick. Set automatically from the chart's own `<YAxis unit>` when unset (the shell threads it through); pass it explicitly only to override. Ignored when `rows` is set — a custom row builder owns its own `TooltipRow.unit` per row. |
valueFormat | ChartValueFormat | STYLE to borrow from the chart's own `<YAxis valueFormat>` for DEFAULT rows (RM-109) — a currency symbol, a percent sign — never abbreviation (`ChartTooltipContent`'s doc). Set automatically from `<YAxis valueFormat>` when unset; ignored when `rows` is set. |
currency | string | ISO 4217 code for `valueFormat`'s `style: "currency"`. |
ChartLegend
| Prop | Type | Description |
|---|---|---|
itemsrequired | LegendItem[] | Legend items to display |
hoveredIndex | number | null | Currently hovered index (for highlight effect) |
onHover | (index: number | null) => void | Callback when an item is hovered |
onItemClick | ( item: LegendItem, index: number, event: React.MouseEvent | React.KeyboardEvent, ) => void | Drill-down on a legend entry (#349). When set, each item renders as a real `<button>` — keyboard operable and named by the item's label — instead of a `<div>`. Unset, the legend is unchanged (a non-interactive `<div>` list). NOTE this lives on `ChartLegend`, not on the chart containers: the legend is a separately-placed composition primitive, so a callback on the container would be a prop the container cannot honour. |
hiddenKeys | ReadonlySet<string> | Series toggle (RM-118, `legend={{ interactive: "toggle" }}`). Set together with `onToggleKey`: every item renders as a real `<button aria-pressed>` — native keyboard support, no extra wiring — and `hiddenKeys` marks which ones read `aria-pressed="false"` and paint dimmed with a struck-through label (WCAG 1.4.1: hidden is never colour-only). Independent of `onItemClick` (drill-down); a container sets one or the other. |
onToggleKey | (key: string, item: LegendItem, index: number) => void | Toggles one item's hidden state. Keyed by `item.key ?? item.label`. |
toggleControl | "item" | "checkbox" | What hides an item when `onToggleKey` is set. `"item"` (default): the whole entry is the `aria-pressed` toggle. `"checkbox"`: the entry stays free for `onItemClick` (a host's selection, say) and a small checkbox after it toggles visibility. The checkbox shows while the row is hovered or holds focus, and always on touch screens, which cannot hover. A hidden entry stays in the legend, muted and struck through, in both modes. |
hideAtDensity | readonly ChartDensity[] | Density tiers that hide the whole legend (RM-072 default: `xs`/`sm`). The container legend engine (`useContainerLegend`, RM-118) passes `["xs"]` — `sm` renders `stack`-laid-out instead of hiding — so this stays `["xs", "sm"]` for every OTHER (direct) caller, unchanged. |
showProgress | boolean | Show progress bars. Default: false |
showMarker | boolean | Show color marker dot. Default: true |
showValue | boolean | Show numeric value column. Default: true |
showPercentage | boolean | Show percentage value. Default: true when showProgress is true |
formatValue | (value: number) => string | Format function for displaying values. Overrides `valueFormat` entirely when set. |
valueFormat | ChartValueFormat | How to format `value`/`maxValue` (RM-109) — a preset or the object form (`{ decimals, abbreviate, sign, prefix, suffix, … }`, `value-format.ts`). Resolved as a SET across every item (#250, `useChartValueSetFormatter`) so the legend never mixes "1K" beside "400". Default: locale-aware plain grouping (`intFmt`), unchanged from before this prop existed. |
currency | string | ISO 4217 code for `valueFormat: "currency"`. Falls back to `ChartConfigProvider`, then `"USD"`. |
maxFractionDigits | number | Most digits after the decimal point in the value column (RM-187). |
locale | string | Locale for the value and percent columns (RM-187); unset, the `LocaleProvider`'s. |
title | string | Title shown above the legend |
layout | "row" | "stack" | "split" | Item flow direction (RM-118, sitting 3). `"stack"` (default — every caller before this prop existed) is byte-identical to before: one item per line. `"row"` wraps items left-to-right (`flex-wrap`), matching the layout `AutoChart`'s old `AutoLegend` used, AND drops the `w-full` an interactive (`onItemClick`/toggle) item otherwise gets — `w-full` inside a row would force every item onto its own line regardless of this prop. `useContainerLegend` (the container legend engine) passes its own resolved `layout` ("row" at `base`/`medium`/`wide`, "stack" at `narrow` or density `sm`) through; a direct caller may set its own or leave it unset for the original stacked behaviour. |
className | string | Additional class name for the container |
titleClassName | string | Class name for the title |
itemClassName | string | Class name for each legend item |
labelClassName | string | Class name for the label |
valueClassName | string | Class name for the value |
renderItem | (props: { item: LegendItem; index: number; isHovered: boolean; isFaded: boolean; percentage: number; }) => ReactNode | Custom render function for legend items. `item.value` may be `NaN`, meaning the item has no value (a container legend entry with no number of its own): check `Number.isFinite(item.value)` before printing it. `percentage` is 0 for such an item. |
splitGroups | readonly ChartLegendSplitGroup[] | `layout="split"` (RM-121): one row per value axis, each led by its side label. Items not named by any group are omitted. Unset, `"split"` renders as `"row"`. |
splitStacked | boolean | Stack the split rows vertically (the narrow tier). Default `false`: side by side, wrapping. |
Theming
The tokens each state resolves to. Change the token and every theme follows.
| State | Token |
|---|---|
| series | --chart-1 … --chart-5 |