import { AreaChart } 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 AreaChart 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 AreaChart up before writing code: `npx -y @elabs-ai/components-cli docs AreaChart` 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 did it change over time? Volume over time.
- measures over time where magnitude matters — stacked, or as a stream with offset="wiggle"
Avoid
- one series, or series that don't add up to a meaningful total — use a line chart; fewer than about 4 points — a bar chart reads the same data faster
- Stacking areas that are not parts of one whole — a stack asserts summation; use lines.
- Overlapping opaque areas — either stack them or switch to a LineChart.
- Leaving status="loading" unhandled — AreaChartLoading is the shipped skeleton.
Works with
Contains
Used inside
Examples
Default
Multi Series
With Accessible Label
Accessible variant — announces label + description to screen readers on focus.
Loading
Categorical X Scale
Streamgraph
`AreaChart offset="silhouette"` — three product lines composed into a streamgraph, centered around zero rather than a hard baseline. Band order (bottom → top) follows JSX order: desktop, tablet, mobile.
Stream With Seams
`seams={2}` — a `--chart-background` stroke drawn between bands, the F16 "paper seam" that visually separates each ribbon from its neighbour. `seams` IS this package's separator-lines feature for stacked areas (Datawrapper's "separator lines" option) — there is no additional `separatorLines` prop.
Hairline Decoration
High decoration (`data-decoration="10"`) on a SINGLE-series `Area`: renders a `HairlineArea` — one 0.55px vertical hairline per sample, a 1.2px crest — instead of the usual pattern fill (lieflat F3 Hairline Area). `labelPeaks` rings the max sample with a filled dot + value label.
Hairline Decoration Off
`data-decoration="0"` (the default) — the same single-series chart renders its ordinary solid fill, byte-identical to `Default` above; no hairlines.
Nulls
`nulls` (RM-112). `"gap"` (the default) breaks the fill/crest at a non-numeric sample; `"connect"` bridges straight across it; `"zero"` (the pre-RM-112 default) reads it as 0 — same three modes, same resolution, as `Line`'s `nulls`.
Symbols
`symbols` (RM-112) — the same shared `resolveSeriesSymbols` rule as `Line symbols`: unset placement on a ≤12-point series defaults to hollow markers at the first/last point only.
Focus on hover
`focusOnHover` (RM-112) dims every OTHER series to `SELECTION_EXCLUDED_OPACITY` while the pointer is over one — same behaviour, same wide invisible hit-stroke, as `Line`'s `focusOnHover`. No `legend` here (the chart's own default configuration): `SeriesFocusTargets` (issue 545) still gives a keyboard user the identical spotlight — Tab lands on one of its invisible-until-focused targets, and focusing it drives the same dim.
Selection states
`selectionStates` paints the host’s tri-state on each category’s column: selected marks carry a compound foreground/background outline, excluded marks dim AND carry a full-opacity dashed frame, so the three states stay distinguishable in greyscale.
Legend toggle
Container legend (RM-118): `legend={{ interactive: "toggle" }}` mounts `ChartLegend` above the plot with real `aria-pressed` buttons — click, or Tab then Enter, hides a series and the y-domain re-tweens around what is left visible. `focusOnHover` reuses the same fade a pointer-hovered area already had for a keyboard-focused legend item (issue 545).
Lived-in: demand desk (rolling mean, σ band, forecast, navigator)
A grid operator's demand view: two years of daily readings, a 7-day rolling mean drawn over the raw fill, a one-standard-deviation band for the usual corridor, and a fortnight's forecast with a weekly season appended at the end. The navigator's axis reaches the forecast horizon, so the default window opens on the last quarter AND the projection; the value axis keeps the full data's domain so a moved window never re-scales the picture.
API
AreaChart
| Prop | Type | Description |
|---|---|---|
datarequired | Record<string, unknown>[] | Data array - each item should have a date field and numeric values |
xDataKey | string | Key in data for the x-axis (date). Default: "date" |
xScale | ChartXScaleType | How `xDataKey` values are interpreted (#352). Default: `"time"`. - `"time"` — Date (or Date-coercible) x values on a time scale. - `"band"` — categorical x values (`"Turn 1"`, `"Step A"`), evenly spaced in first-seen order. Axis ticks, the ticker and the tooltip title all show your own value, not a formatted date. - `"linear"` — numeric x values spaced by magnitude. Omitting it keeps today's behaviour, except that a dataset whose x values are ALL non-Date-coercible degrades to `"band"` (with a dev warning) instead of collapsing. |
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 clip-reveal. Default: cubic-bezier(0.85, 0, 0.15, 1) |
enterTransition | Transition | Motion enter transition (spring or cubic-bezier tween). |
revealSignature | string | Signature of motion URL state — triggers reveal 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 reveal at width 0 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 — drives chart phase and loading chrome. Default: `"ready"`. |
loadingLabel | string | Centered shimmer label while loading. |
yDomainTweenDuration | number | Animate y-domain over this duration (ms) on status transitions. Default: 500. |
yDomainTween | boolean | Animate y-domain when status or target domain changes. Default: true |
xDomain | [Date, Date] | Visible x-domain for brush zoom. |
xDomainSlotCount | number | Full dataset length for x-scale padding when `xDomain` is set. |
tweenYDomainOnXDomainChange | boolean | Tween y-domain when brush changes the visible x-range. Default: false |
style | CSSProperties | Inline container styles (e.g. fixed height for brush strip). |
onPhaseChange | (phase: ChartPhase) => void | Fires when the internal chart phase changes (e.g. OG capture readiness). |
childrenrequired | ReactNode | Child components (Area, Grid, ChartTooltip, etc.) |
onDatapointClick | ChartDatapointClickHandler | Drill-down (#349). Fires when a datapoint 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. Leaving it unset changes nothing: no extra DOM, no new focusables. |
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). |
offset | AreaStackOffset | Streamgraph baseline (RM-029) — maps to `d3-shape`'s `stackOffsetNone` / `Silhouette` / `Wiggle` / `Expand`. Unset (default): no stacking — every child `Area` renders independently, exactly as today. Set it to stack every child `Area` (in JSX order) using that baseline; `"silhouette"` is the F16 lieflat "Stream Ribbon" look. |
seams | number | Paper gap between stacked bands, in px — a `--chart-background` stroke drawn along each band's own top edge. Only takes effect when `offset` is set. Default: 0 (no seam). 2 is the F16 lieflat value. When set (> 0), the seam owns the band's edge (#245): the band's own crest stroke is suppressed there so the paper gap is what separates the ribbons, rather than the two painting the same path on top of each other. |
labelBands | boolean | Label each stacked band with its series name at the band's widest x (`HaloText`, clamped inside the plot). Only takes effect when `offset` is set. Default: false. |
nulls | NullsMode | Container-level default for an `Area`'s own `nulls` prop (RM-112). Unset — every `Area` keeps its own default (`"gap"`). |
focusOnHover | boolean | Hovering (or, on touch, tapping) one series dims every other series to the shared selection-excluded opacity (RM-112, `dw-river.md` §2.3). Default false — today's behaviour. |
legend | ContainerLegendProp | Legend engine (RM-118): `true` or a config object mounts `ChartLegend` beside the plot via `useContainerLegend`; `{ interactive: "toggle" }` hides a band and re-tweens the y-domain. Unset (default) renders NOTHING new (R1, moved into `useContainerLegend` itself) — RM-110's end labels stay the default multi-series key for `AreaChart`. `{ values: true }` prints each series' own last point inside the visible x window (never a stack total), in the format of the `YAxis` on its `yAxisId`; plain numbers when the series' axes format differently. |
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. |
palette | ChartPalette | Colour ramp for the series (RM-186): each series child that sets no colour of its own takes the next colour of `resolvePalette(palette, n)`. Unset: every such series keeps `--chart-line-primary`, as before. |
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. |
hoverCategory | ChartHoverCategory | The category hovered in a SIBLING chart (or by the host). `null`/unset → none. |
onHoverCategory | (category: ChartHoverCategory) => void | Fires with the category under the pointer on move, and `null` on leave. |
scrollbar | ChartScrollbarMode | Strip style. Default `"none"` — a chart never grows a strip on its own (ADR 0040 decision b); a `window` / `defaultWindow` turns it on, as does `"miniChart"` / `"bar"` / `"auto"`. |
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. |
maxVisiblePoints | number | Time-series families: with `scrollbar="auto"`, rows above this show the strip. Default 2000. |
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. |
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. |
Area
| Prop | Type | Description |
|---|---|---|
dataKeyrequired | string | Key in data to use for y values |
yAxisId | string | number | Y-scale group id (Recharts `yAxisId`). Default: `"left"`. |
fill | string | Fill color for the area gradient start. Default: var(--chart-line-primary) |
fillOpacity | number | Fill opacity at the top of the area. Default: 0.4 |
stroke | string | Stroke color for the line. Default: same as fill |
strokeWidth | number | Stroke width. Default: 2 |
curve | CurveFactory | CurveAlias | Curve interpolation — a named alias (`"linear"` | `"monotone"` | `"natural"` | `"step"` | `"step-before"` | `"step-after"`, RM-112) or a raw `@visx/curve` factory. Default: `"monotone"` (unchanged). |
animate | boolean | Whether to animate the area. Default: true |
showLine | boolean | Whether to show the stroke line. Default: true |
showHighlight | boolean | Whether to show highlight segment on hover. Default: true |
gradientToOpacity | number | Gradient opacity at bottom. Default: `0` (fully transparent) for an ordinary, unstacked area — the bottom edge is the y-axis baseline, not the encoding, so fading toward it costs no information. For a STACKED band (`AreaChart offset` set, #245) the default instead follows `fillOpacity` — a flat wash — because in a stacked/stream area BOTH edges are the encoding (band thickness is the value) and fading one away destroys it. Pass an explicit value (including `0`) to override either default. |
gradientSpan | number | Vertical extent of the fill gradient (0–1). `1` fades across the full height; lower values compress the gradient toward the top. |
fadeEdges | FadeEdges | Fade the area fill (and stroke) toward transparent at the chart edges. - `true` fades both edges, `false` disables the fade entirely. - `"left"` / `"right"` fades only that side — useful when the opposite edge butts up against another element you don't want to fade into. Default: false |
showMarkers | boolean | Render scatter-style circle markers at each data point. Default: false |
markers | SeriesPointMarkerStyle | Marker styling (same options as Scatter). |
symbols | SeriesSymbolsSpec | Placement/style wrapper over `showMarkers`/`markers` (RM-112) — same shape and resolution rule as `Line symbols` (shared helper, `resolveSeriesSymbols`): unset → no symbols; set without a `placement` on a series with more than 12 points → also no symbols (avoid symbols on a dense, regularly-sampled series); otherwise `placement` defaults `"ends"`, `style` defaults `"hollow"`. Setting this turns markers on regardless of `showMarkers`. |
dashFromIndex | number | Data index from which the line stroke becomes dashed (inclusive). Useful for projecting incomplete periods, e.g. dashed from yesterday through today. |
dashArray | string | Dash pattern for the tail segment when `dashFromIndex` is set. Default: "6,4" |
nulls | NullsMode | How this area draws a non-numeric sample (RM-112). Overrides the container-level `AreaChart nulls` default. Unset — read the container default, or `"gap"` with no container default (a visible break in the fill/crest at that sample, never a silent zero). |
loadingStroke | string | Pulse stroke color while chart is loading. Default: var(--chart-foreground) |
loadingStrokeOpacity | number | Pulse stroke opacity while chart is loading. Default: 0.5 |
loading | boolean | Show the loading pulse overlay. Default: follows chart loading phase. Set `false` to disable even during loading. |
loadingPulseMode | LineLoadingPulseMode | Override pulse animation mode (loop / exit / enter). |
labelPeaks | LabelPeaksSpec | boolean | `true` rings the peak sample with a filled dot + value label (RM-029) — only takes effect when this `Area` renders as a `HairlineArea`, a single-series chart under high decoration (`data-decoration` ≥ 8). A number or `{ count, minGap? }` instead labels the top-k highest points, the SAME engine `Line.labelPeaks` uses — never a forked copy. Default: `false` — no peak label, today's behaviour. |
name | string | Series display name — the text of its end label, key item and auto summary (RM-110). Default: `dataKey`. |
seriesLabel | Responsive<SeriesLabelMode> | Where the series names itself (RM-110): `"end"` | `"key"` | `"none"`, or a `Responsive` value. Default: as `LineProps.seriesLabel` (two or more series, and only for a series with a real `name`). Read by the chart shell, which reserves the margin and places every label in one pass. |
valueLabels | ChartValueLabels | Automatic value labels (RM-110) — see `LineProps.valueLabels`. |
AreaBand
| Prop | Type | Description |
|---|---|---|
lowKey | string | Key in data for the band's lower edge. Ignored (and optional) when `from="zero"` — the low edge is the value-axis zero line instead. |
highKeyrequired | string | Key in data for the band's upper edge. |
from | "zero" | Bracket the band between `highKey` and the value-axis zero line instead of a second series (Datawrapper: area fill "between a line and zero"). `lowKey` is ignored when set. |
fill | string | Fill colour. Default `var(--chart-ring-background)` — the same quiet "normal range" wash `Sparkline`'s `band` prop already draws with. |
fillOpacity | number | Fill opacity. Default 1 — the token itself already carries the wash. |
negativeFill | string | Fill colour for any segment where the high edge dips BELOW the low edge (`highKey < lowKey`, or `highKey < 0` under `from="zero"`) — Datawrapper's negative-difference fill (River bar-line combination recipe). Unset: the whole band paints `fill` regardless of sign — today's behaviour. |
curve | CurveFactory | CurveAlias | Curve function, matching the series it brackets. Default `curveMonotoneX`. |
yAxisId | string | number | Y-scale group id (Recharts `yAxisId`). Default: `"left"`. |
className | string |
AreaChartLoading
| Prop | Type | Description |
|---|---|---|
margin | Partial<Margin> | Chart margins |
stroke | string | Stroke color for the animated loading segment. |
strokeOpacity | number | Stroke opacity for the animated loading segment. Default: 0.5 |
gridStroke | string | Grid line stroke (color and opacity via color-mix or oklch alpha). |
gridShimmerStroke | string | Shimmer band stroke (color and opacity via color-mix or oklch alpha). |
gridShimmer | boolean | Animate a shimmer band across grid lines. Default: true |
gridShimmerLength | number | Shimmer band width in pixels. Default: 140 |
gridShimmerSpeed | number | Shimmer speed multiplier (higher = faster). Default: 1 |
gridShimmerSync | boolean | Match shimmer loop to the loading line pulse (cycle + inter-loop pause). |
label | string | Centered shimmer label text. Default: "Loading" |
aspectRatio | string | Aspect ratio as "width / height". Default: "2 / 1" |
plotHeight | Responsive<ChartPlotHeight> | The plot height, as on the chart it stands in for — px, `{ aspect }`, or per breakpoint. Wins over `aspectRatio`, so the placeholder holds the box the loaded chart will fill. |
className | string | Additional class name for the container |
XAxis
| Prop | Type | Description |
|---|---|---|
numTicks | number | @deprecated Use `tickCount` — `numTicks` still wins when both are set, exactly as before (ADR 0042 A.2, row 6). Read until 7.0.0, with one development warning. |
tickCount | AxisTickCount | Tick target (RM-108). `"auto"` (default) derives it from the plot width — `tickTargetForWidth(innerWidth)`, about one tick per 90 px, clamped 2–10, and never more than the number of data rows on a time axis (6 monthly rows get at most 6 ticks, not 9 labels between them). |
ticks | Date[] | number[] | RM-108 naming, shared with `YAxis`. On a time axis: an alias of `tickValues` (`tickValues` wins). On a numeric x with `domain`/`scale` (ScatterChart): exactly these raw x values. |
domain | AxisDomain | Numeric x only (ScatterChart with numeric `xDataKey`, RM-108): pin either end of the x domain in raw units; `"auto"` keeps the data-derived end. Read by the chart container, so place `XAxis` as a direct child. Setting `domain` or `scale` also switches the labels from one per data row to a numeric ruler. Ignored on a time axis. |
scale | ValueScaleType | Numeric x only (RM-108): `"linear"` (default), `"log"` (refuses data or a domain touching 0 — dev warning, renders linear) or `"sqrt"`. |
position | XAxisOrientation | Which edge the labels sit on (RM-108). Default: `"bottom"`. |
orientation | XAxisOrientation | @deprecated Use `position` — the same values (ADR 0042 A.2, row 10). Read until 7.0.0, with one development warning; when both are set, `position` wins. |
title | ReactNode | Axis title (RM-108). |
titlePlacement | AxisTitlePlacement | `"outside"` (default) — in the margin beyond the tick labels, at the far end; `"inside"` — `HaloText` at the far end inside the plot. |
tickerHalfWidth | number | Width of the date ticker box for fade calculation. Default: 50 |
tickMode | "domain" | "data" | `"domain"` — evenly spaced ticks across the time domain (default). `"data"` — one label per data row at its x value (better with sparse or monthly bars). |
tickFormat | (value: Date) => string | Override the default `Intl`-based tick label formatter. Applied to every tick this axis renders (generated or `tickValues`). #357. **Time scale only.** Ignored (with a dev warning) when the chart runs `xScale="band" | "linear"` — those modes project onto a synthetic instant, so a `Date` formatter would print a fabricated calendar date instead of your x value. Format categorical/numeric x values in your data. #352. |
dateFormat | DateFormatPreset | ((value: Date) => string) | The date-format LADDER (RM-109): a preset from `date-format.ts` (`"year"` → `"yearShort"` → `"month"` → `"day"` → `"weekday"` → `"hour"` → `"minute"`), or a formatter function for full control. Unset (default) — the axis picks a rung itself via `dateFormatForSpan`, from the time domain's span and how many ticks are on screen, instead of the old fixed `"Mon d"` shape whatever the span. A ten-year series reads years; a 36-hour series reads hours. `tickFormat` still wins outright when both are set — it is the raw escape hatch this package has always had; `dateFormat` is the smart default underneath it. Same time-scale-only caveat as `tickFormat` (#352). |
tickValues | Date[] | Render exactly these tick positions, bypassing tick generation AND the default label-collision de-dupe entirely — use when the default de-dupe would collapse the axis (e.g. dense data whose formatted labels collide). #357. **Time scale only** — see `tickFormat`. #352. |
periodTicks | XAxisPeriodTicks | false | Draw a `HairlineFloor` (RM-017) below the plot — one hairline tick per calendar period, whether or not a data row falls on it, with the long tick anchored to a real calendar boundary (day → the first day of the week, week → the first week of the month, month → January), not an index stride from wherever the series happens to start (#253). Lieflat provenance: the ruled foot of a ledger page gives a reader the passage of time with no labels and no axis. This is a SEPARATE visual layer from the labelled ticks above (`numTicks` / `tickMode`) — it never changes which labels render or where. `false` (default) draws nothing — today's behaviour. |
YAxis
| Prop | Type | Description |
|---|---|---|
yAxisId | string | number | Scale group id (Recharts `yAxisId`). Default: `"left"`. |
position | YAxisOrientation | Which side of the chart to render labels. Default: `"left"`. |
orientation | YAxisOrientation | @deprecated Use `position` — the same values (ADR 0042 A.2, row 11). Read until 7.0.0, with one development warning; when both are set, `position` wins. |
numTicks | number | @deprecated Use `tickCount` — `numTicks` still wins when both are set, exactly as before (ADR 0042 A.2, row 7). Clamped to {@link Y_AXIS_MIN_TICK_COUNT}–{@link Y_AXIS_MAX_TICK_COUNT}. Read until 7.0.0, with one development warning. |
tickCount | AxisTickCount | Tick target (RM-108). `"auto"` (default) derives it from the plot height — `tickTargetForHeight(innerHeight)`: 3 under 200 px, else 5. |
ticks | number[] | Render exactly these tick values (RM-108), bypassing generation. |
domain | AxisDomain | Pin either end of the value domain (RM-108); `"auto"` keeps the data-derived end. Read by the chart container, so place `YAxis` as a direct child. On a length encoding (bars) the domain always includes 0 — a non-zero lower bound is ignored with a dev warning (`charts-honesty`). |
scale | ValueScaleType | How values map to pixels (RM-108). `"log"` refuses data or a domain that touches 0 (dev warning, renders linear); bars are linear only. Default: `"linear"`. |
title | ReactNode | Axis title — names the unit of every tick (RM-108). |
titlePlacement | AxisTitlePlacement | `"outside"` (default) — above the top tick label in the margin; `"inside"` — `HaloText` at the top of the axis inside the plot. |
labelPlacement | AxisLabelPlacement | `"outside"` (default) — tick labels in the margin beside the plot; `"inside"` — labels sit just above their grid line inside the plot. |
valueFormat | ChartValueFormat | How tick values are rendered. Default: `"compact"` — `1.5M`, not `1500k` and not `1500000`. Pass `"number"` for every digit. |
currency | string | ISO 4217 code for `valueFormat: "currency"`. Falls back to `ChartConfigProvider`, then `"USD"`. |
formatValue | (value: number) => string | Custom formatter for tick labels. Overrides `valueFormat` entirely when set. |
unit | string | Unit text appended to {@link unitOn} tick(s) — `<YAxis unit="%" />` paints `"80 %"` on that tick, not every tick (RM-109). The tooltip is the place a unit repeats on every value (the blog's "3.4 % unemployed", not a bare "3.4 %"); see `TooltipRow.unit`. |
unitOn | "last" | "first" | "all" | Which tick(s) {@link unit} paints on. Default: `"last"`. |
matchSeriesColor | boolean | Paint the tick labels and title in the colour of this axis' series when it carries exactly ONE series; neutral otherwise (RM-121, Datawrapper's "label colour: match data"). The text goes through `seriesLabelInk` — the stroke mixed toward the label ink so it still reads at 4.5:1. Default `false`. |
sideLabel | ReactNode | "auto" | A caption naming which scale this is, above the tick column (RM-121). `"auto"` → "Left scale" / "Right scale" by `position`, through the locale seam (`charts.axis.leftScale` / `charts.axis.rightScale`). |
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"`. |
Theming
The tokens each state resolves to. Change the token and every theme follows.
| State | Token |
|---|---|
| status | status="loading" → AreaChartLoading skeleton; "ready" → the plot |