# Chart (/docs/chart)





`Chart` wraps [TanStack Charts](https://tanstack.com/charts)' own `<Chart>` (`@tanstack/charts/react`) — a typed, tree-shakable grammar for SVG charts. TanStack owns everything about *building* a chart: `defineChart`, marks (`lineY`, `barY`, `areaY`, …), scales, transforms, interactions, and the actual rendering. This component only makes the result look native to the kit — light/dark chrome, a themed DOM tooltip, and an optional categorical palette — so you build charts with TanStack's real API and never learn a second one.

<Alert
  type="info"
  title="Optional peer dependency, alpha library"
  description="
  <>
    <code>@tanstack/charts</code> is an optional peer dependency — install it yourself (<code>npm install @tanstack/charts</code>)
    alongside <code>@42-central/ui-react</code>, the same way <a href=&#x22;/docs/data-table&#x22;>DataTable</a> works with{&#x22; &#x22;}
    <code>@tanstack/react-table</code>. It's still pre-1.0 (alpha) as of this writing: the{&#x22; &#x22;}
    <a href=&#x22;https://tanstack.com/charts&#x22;>TanStack Charts docs</a> are the source of truth for its own API, and it's worth
    pinning an exact version.
  </>
"
/>

```tsx
import { barY, defineChart } from '@tanstack/charts';
import { scaleBand } from '@tanstack/charts/scales/band';
import { scaleLinear } from '@tanstack/charts/scales/linear';
import { tooltip } from '@tanstack/charts/tooltip';
import { Chart } from '@42-central/ui-react/chart';
import '@42-central/ui-react/chart/styles.css';

const data = [
  { month: 'Apr', commits: 142 },
  { month: 'May', commits: 187 },
  { month: 'Jun', commits: 165 },
];

const definition = defineChart({
  marks: [barY(data, { x: 'month', y: 'commits', inset: 2 })],
  scales: {
    x: { scale: () => scaleBand().padding(0.24) },
    y: { scale: scaleLinear, nice: true, grid: true, axis: { label: 'Commits' } },
  },
  tooltip,
});

<Chart definition={definition} ariaLabel="Commits per month" height={280} />
```

<Alert
  type="info"
  title="Ship the stylesheet"
  description="
  <>
    <code>@42-central/ui-react/chart/styles.css</code> is a separate, opt-in stylesheet — not part of the universal{&#x22; &#x22;}
    <code>styles.css</code>/<code>theme.css</code>/<code>colors.css</code> chain every consumer already imports. Only apps
    that render a <code>Chart</code> need TanStack's tooltip/chrome variables mapped to the kit's tokens, so it ships on its
    own.
  </>
"
/>

Chart type variety — magnitude, trend, relationship, distribution, composition — lives on [chart types](/docs/chart/types); wiring a chart's own interactions (click-to-select, an animated hover marker) lives on [interactions](/docs/chart/interactions). This page covers what `Chart` itself adds: theming and its own prop API.

## Theming [#theming]

Chrome — axis, grid lines, the frame, the legend, the crosshair — already renders through TanStack's own `currentColor`; `Chart` sets `color` on its root so it tracks the kit's `[data-theme]` toggle instead of the OS `prefers-color-scheme` TanStack's un-themed default would otherwise follow. The DOM tooltip's surface, border, shadow, and font theme through TanStack's own `--ts-chart-tooltip-*` custom properties, matched to the kit's floating-panel surface (the same brand-tinted recipe [`Popover`](/docs/popover) uses).

## Series color [#series-color]

A one-series chart paints with its palette's chart fill. `color` sets `data-color` on the chart's root, so the fill is that palette's — `neutral` included, black in light mode and white in dark:

<Preview align="block" code="&#x22;<Chart definition={chart} ariaLabel=\&#x22;Commits per month\&#x22; height={200} color=\&#x22;blue\&#x22; />\n<Chart definition={chart} ariaLabel=\&#x22;Commits per month\&#x22; height={200} color=\&#x22;purple\&#x22; />\n<Chart definition={chart} ariaLabel=\&#x22;Commits per month\&#x22; height={200} color=\&#x22;orange\&#x22; />\n<Chart definition={chart} ariaLabel=\&#x22;Commits per month\&#x22; height={200} color=\&#x22;neutral\&#x22; />&#x22;">
  <ColorAccentDemo />
</Preview>

Without `color`, it inherits the nearest ancestor's `data-color` instead, like a `Button` or a `Progress` would — and with no ancestor palette at all, it falls back to the kit's default, `neutral`:

<Preview align="block" code="&#x22;<div data-color=\&#x22;green\&#x22;>\n  <Chart definition={chart} ariaLabel=\&#x22;Commits per month\&#x22; height={200} />\n</div>&#x22;">
  <InheritedColorDemo />
</Preview>

The chart fill is not quite `--c-solid`, the variable a `Button` fills with. A button's label sits *on* its fill; a chart mark has nothing on it, so what has to read is the fill against the page. In light mode, most 500 solids fall under the 3:1 contrast that non-text graphics need, so in light mode chart fills use the **600** step. Yellow, whose solid is already 400, uses 700. In dark mode, the fill is the solid, unchanged. `chart/styles.css` holds the per-color map (`--chart-<name>`), and both the single-series fill (`--chart-solid`) and the `colors` slots read from it.

Only a chart with no color channel follows the inherited fill — one whose marks never map a field to `color`. A chart whose `definition` sets its own `color` options (a `range`, a `scale`), or that's built from a `defineChart` function, keeps TanStack's own resolution untouched.

`colors` themes a multi-series chart, one `--ts-chart-N` slot per entry — TanStack's own default categorical scale picks these up with zero changes to how a chart's `definition` builds its color channel (see [Commits by contributor](/docs/chart/types#composition) for the full working example):

```tsx
<Chart definition={definition} ariaLabel="Commits by contributor" colors={['blue', 'green', 'red']} />
```

`chartColors(colors?)` — exported alongside `Chart` — resolves an ordered `Color[]` (default `CHART_PALETTE`) to CSS values (`var(--chart-<name>)` for a kit color, so the light/dark step comes along), for building an explicit scale yourself:

```tsx
import { chartColors, CHART_PALETTE } from '@42-central/ui-react/chart';

defineChart({
  // ...
  color: {
    domain: ['Open', 'In progress', 'Closed'],
    range: chartColors(['orange', 'blue', 'green']),
  },
});
```

`CHART_PALETTE` leads with `blue`/`green`/`red`/`pink` — the only 4-combination of this kit's own hues where every pair (not just adjacent ones) clears a colorblind-safety check. The remaining five hues (`orange`, `purple`, `teal`, `yellow`, `cyan`) are still available for a 5th+ series — pair them with a legend or direct labels, which every multi-series example on the [chart types](/docs/chart/types) page already ships.

## API [#api]

<TypeTable
  type="{
  definition: {
    type: &#x22;DomChartDefinition<TDatum, TXValue, TYValue>&#x22;,
    description: &#x22;The chart, built with TanStack's own defineChart/marks/scales — imported directly from @tanstack/charts.&#x22;,
  },
  ariaLabel: {
    type: &#x22;string&#x22;,
    description: &#x22;Required — TanStack's own accessible name for the chart.&#x22;,
  },
  ariaDescription: {
    type: &#x22;string&#x22;,
    description: &#x22;Optional longer description.&#x22;,
  },
  height: {
    type: &#x22;number&#x22;,
    description: &#x22;Fixed pixel height. Omit and pair with aspectRatio + initialWidth for proportional sizing instead.&#x22;,
  },
  aspectRatio: {
    type: &#x22;number&#x22;,
    description: &#x22;Width/height ratio, used with initialWidth when height is omitted.&#x22;,
  },
  width: {
    type: &#x22;number&#x22;,
    description: &#x22;Fixed pixel width. Omit to fill the container.&#x22;,
  },
  initialWidth: {
    type: &#x22;number&#x22;,
    default: &#x22;640&#x22;,
    description: &#x22;First-paint width before the container is measured (avoids a layout jump).&#x22;,
  },
  color: {
    type: &#x22;Color&#x22;,
    description: &#x22;Single accent for a one-series chart — sets data-color, which the series paints with through --chart-solid (the 600 step in light mode, --c-solid in dark). Omit it to inherit an ancestor's data-color.&#x22;,
  },
  colors: {
    type: &#x22;Color[]&#x22;,
    default: &#x22;CHART_PALETTE&#x22;,
    description: &#x22;Ordered palette for a multi-series chart — sets --ts-chart-1..N.&#x22;,
  },
  renderSvg: {
    type: &#x22;ChartSvgRenderer&#x22;,
    description: &#x22;Plain SVG paint function. Ignored when renderer is given.&#x22;,
  },
  renderer: {
    type: &#x22;ChartRenderer&#x22;,
    description: &#x22;A full custom renderer, e.g. motion() from @tanstack/charts/motion — needed for continuous focus/crosshair motion between points. See Interactions.&#x22;,
  },
  onFocusChange: {
    type: &#x22;(point: ChartPoint | null) => void&#x22;,
    description: &#x22;Fires as keyboard/pointer focus moves between points.&#x22;,
  },
  onSelect: {
    type: &#x22;(point: ChartPoint | null) => void&#x22;,
    description: &#x22;Fires when a point is selected (click/Enter).&#x22;,
  },
  onRender: {
    type: &#x22;(context: ChartRenderContext) => void&#x22;,
    description: &#x22;Fires after each render, with the raw SVG/scene — an escape hatch for anything this wrapper doesn't expose.&#x22;,
  },
  testId: {
    type: &#x22;string&#x22;,
    description: &#x22;Renders as data-testid on the wrapping root.&#x22;,
  },
  className: {
    type: &#x22;string&#x22;,
    description: &#x22;Classes for the wrapping root.&#x22;,
  },
  style: {
    type: &#x22;CSSProperties&#x22;,
    description: &#x22;Inline styles for the wrapping root, merged after the palette's own CSS custom properties.&#x22;,
  },
}"
/>
