---
id: "packages/active-charts/theming"
title: "Theming"
description: "The CSS tokens a chart reads, the package defaults, and how this site uses active-ui's tokens so charts and components share one visual system."
url: "/packages/active-charts/theming"
locale: "en"
revision: "4d0c034ada04d325"
---

# Theming

A chart has no theme prop and no provider for colour. It reads CSS custom properties from the page:

- **Chart tokens**: `--chart-1` to `--chart-10` for series, `--chart-positive`, `--chart-negative`
  and `--chart-caution` for meaning, `--chart-sequential-*` and `--chart-diverging-*` for scales,
  `--chart-on-fill-light` and `--chart-on-fill-dark` for labels on a mark.
- **Semantic tokens of the host**: surfaces, text, borders and focus (`--background`,
  `--foreground`, `--popover`, `--border`, `--ring`, …) for tooltips, menus, tables and focus.

When the host sets none, the package's stylesheet gives complete light and dark defaults.

## On this site

active-ui defines the chart tokens next to its other tokens, in light and dark, so every chart on
this site takes its colours from the same system as the components beside it; there is no mapping
file and no second palette. Switch the colour scheme of this site to see the charts follow.

**Example: Every chart family**

Client: Runs entirely in your browser. Source: `examples/charts/families.tsx`.

```tsx
// apps/docs/examples/charts/families.tsx
'use client';

import {useState, type ReactNode} from 'react';
import {
  BEFORE_AFTER,
  DAILY_PRICES,
  DELIVERY_DAYS,
  DELIVERY_SPREAD,
  FLOW_LINKS,
  FLOW_NODES,
  FUNNEL,
  MILESTONES,
  MONTHLY_SALES,
  ORGANISATION,
  PRICE_VS_RATING,
  PRODUCT_TREE,
  PROFIT_BRIDGE,
  SALES_SERIES,
  SHARE_BY_REGION,
  SKILL_SERIES,
  SKILLS,
  TEMPERATURE_BAND,
  WEEKDAY_ORDERS,
} from '@/lib/examples/chart-data';

import {
  AreaChart,
  BarChart,
  BoxPlotChart,
  BulletChart,
  CandlestickChart,
  ChartDefaults,
  DumbbellChart,
  englishChartTranslator,
  FunnelChart,
  GaugeChart,
  HeatmapChart,
  Histogram,
  LinearGauge,
  LineChart,
  LollipopChart,
  NightingaleChart,
  OhlcChart,
  OrgChart,
  PieChart,
  RadarChart,
  RadialBarChart,
  RangeAreaChart,
  RangeBarChart,
  SankeyChart,
  ScatterChart,
  Sparkline,
  SunburstChart,
  TimelineChart,
  TreemapChart,
  WaterfallChart,
} from '@workspace/active-charts';
import {
  Field,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';
import {
  NativeSelect,
  NativeSelectOptGroup,
  NativeSelectOption,
} from '@workspace/active-ui/components/primitives/native-select';

const H = 280;
const PRICE = {kind: 'price', currency: 'EUR', decimals: 2} as const;

/** Every public chart family, grouped by the archetype that shapes its props. */
const FAMILIES: Record<string, Record<string, () => ReactNode>> = {
  Cartesian: {
    Line: () => (
      <LineChart
        data={MONTHLY_SALES}
        xKey="month"
        xAxis="category"
        series={SALES_SERIES}
        legend
        height={H}
      />
    ),
    Area: () => (
      <AreaChart
        data={MONTHLY_SALES}
        xKey="month"
        xAxis="category"
        series={SALES_SERIES}
        stacked
        legend
        height={H}
      />
    ),
    Bar: () => (
      <BarChart
        data={MONTHLY_SALES}
        xKey="month"
        xAxis="category"
        series={SALES_SERIES}
        legend
        height={H}
      />
    ),
    Histogram: () => (
      <Histogram
        data={DELIVERY_DAYS}
        xKey="days"
        name="Orders"
        binCount={8}
        height={H}
      />
    ),
    Scatter: () => (
      <ScatterChart
        data={PRICE_VS_RATING}
        xKey="price"
        xAxis={{type: 'number', title: 'Price'}}
        yKey="rating"
        name="Products"
        yAxis={{title: 'Rating'}}
        height={H}
      />
    ),
    Candlestick: () => (
      <CandlestickChart
        data={DAILY_PRICES}
        xKey="date"
        xAxis={{temporalSemantic: 'calendarDate'}}
        openKey="open"
        highKey="high"
        lowKey="low"
        closeKey="close"
        name="Price"
        yAxis={{valueSemantics: PRICE}}
        height={H}
      />
    ),
    OHLC: () => (
      <OhlcChart
        data={DAILY_PRICES}
        xKey="date"
        xAxis={{temporalSemantic: 'calendarDate'}}
        openKey="open"
        highKey="high"
        lowKey="low"
        closeKey="close"
        name="Price"
        yAxis={{valueSemantics: PRICE}}
        height={H}
      />
    ),
    'Range area': () => (
      <RangeAreaChart
        data={TEMPERATURE_BAND}
        xKey="month"
        xAxis="category"
        yLowKey="low"
        yHighKey="high"
        name="Temperature"
        height={H}
      />
    ),
    'Range bar': () => (
      <RangeBarChart
        data={TEMPERATURE_BAND}
        xKey="month"
        xAxis="category"
        yLowKey="low"
        yHighKey="high"
        name="Temperature"
        height={H}
      />
    ),
    'Box plot': () => (
      <BoxPlotChart
        data={DELIVERY_SPREAD}
        xKey="carrier"
        xAxis="category"
        minKey="min"
        q1Key="q1"
        medianKey="median"
        q3Key="q3"
        maxKey="max"
        outliersKey="out"
        name="Delivery days"
        height={H}
      />
    ),
    Dumbbell: () => (
      <DumbbellChart
        data={BEFORE_AFTER}
        xKey="team"
        xAxis="category"
        yLowKey="before"
        yHighKey="after"
        lowName="2025"
        highName="2026"
        height={H}
      />
    ),
    Lollipop: () => (
      <LollipopChart
        data={MONTHLY_SALES}
        xKey="month"
        xAxis="category"
        yKey="online"
        name="Online"
        height={H}
      />
    ),
    Waterfall: () => (
      <WaterfallChart
        data={PROFIT_BRIDGE}
        xKey="step"
        yKey="amount"
        kindKey="kind"
        name="Profit"
        height={H}
      />
    ),
    Heatmap: () => (
      <HeatmapChart
        data={WEEKDAY_ORDERS}
        xKey="day"
        yKey="part"
        colorKey="orders"
        name="Orders"
        label={{enabled: true}}
        height={H}
      />
    ),
  },
  Categorical: {
    Pie: () => (
      <PieChart
        data={SHARE_BY_REGION}
        valueKey="value"
        categoryKey="region"
        name="Share"
        legend
        height={H}
      />
    ),
    Funnel: () => (
      <FunnelChart
        data={FUNNEL}
        valueKey="count"
        categoryKey="stage"
        name="Visitors"
        height={H}
      />
    ),
    'Radial bar': () => (
      <RadialBarChart
        data={SHARE_BY_REGION}
        valueKey="value"
        categoryKey="region"
        name="Share"
        height={H}
      />
    ),
    Nightingale: () => (
      <NightingaleChart
        data={SHARE_BY_REGION}
        valueKey="value"
        categoryKey="region"
        name="Share"
        legend
        height={H}
      />
    ),
    Radar: () => (
      <RadarChart
        data={SKILLS}
        categoryKey="skill"
        series={SKILL_SERIES}
        min={0}
        max={10}
        legend
        height={H}
      />
    ),
  },
  'Hierarchy and flow': {
    Treemap: () => <TreemapChart data={PRODUCT_TREE} height={H} />,
    Sunburst: () => <SunburstChart data={PRODUCT_TREE} height={H} />,
    Sankey: () => (
      <SankeyChart nodes={FLOW_NODES} links={FLOW_LINKS} height={H} />
    ),
    'Organisation chart': () => (
      <OrgChart data={ORGANISATION} direction="horizontal" height={320} />
    ),
    Timeline: () => <TimelineChart data={MILESTONES} height={220} />,
  },
  Scalar: {
    Gauge: () => (
      <GaugeChart
        value={72}
        min={0}
        max={100}
        zones={[
          {from: 0, to: 40, color: 'var(--chart-negative)', label: 'low'},
          {from: 40, to: 75, color: 'var(--chart-caution)', label: 'fair'},
          {from: 75, to: 100, color: 'var(--chart-positive)', label: 'good'},
        ]}
        label="Satisfaction"
        height={220}
      />
    ),
    'Linear gauge': () => (
      <LinearGauge
        value={68}
        min={0}
        max={100}
        target={75}
        label="Budget used (%)"
        height={120}
      />
    ),
    Bullet: () => (
      <BulletChart
        value={82}
        min={0}
        max={120}
        target={100}
        label="Orders vs target"
        height={90}
      />
    ),
    Sparkline: () => (
      <Sparkline
        data={MONTHLY_SALES.map((row) => row.online)}
        width={220}
        height={48}
        type="area"
        showLastPoint
      />
    ),
  },
};

const ALL = Object.entries(FAMILIES).flatMap(([group, members]) =>
  Object.keys(members).map((name) => ({group, name})),
);

/** The public chart families, each with small fixed data; pick one to draw it. */
export default function ChartFamilies() {
  const [choice, setChoice] = useState('Cartesian/Line');
  const [group, name] = choice.split('/') as [string, string];
  const render = FAMILIES[group]![name]!;
  return (
    <div className="flex w-full flex-col gap-4">
      <Field className="max-w-xs">
        <FieldLabel htmlFor="chart-family">Chart family</FieldLabel>
        <NativeSelect
          id="chart-family"
          className="w-full"
          value={choice}
          onChange={(event) => setChoice(event.target.value)}
        >
          {Object.keys(FAMILIES).map((g) => (
            <NativeSelectOptGroup key={g} label={g}>
              {ALL.filter((entry) => entry.group === g).map((entry) => (
                <NativeSelectOption
                  key={entry.name}
                  value={`${g}/${entry.name}`}
                >
                  {entry.name}
                </NativeSelectOption>
              ))}
            </NativeSelectOptGroup>
          ))}
        </NativeSelect>
      </Field>
      <ChartDefaults locale="en-GB" t={englishChartTranslator}>
        <div key={choice} data-chart-family={choice}>
          {render()}
        </div>
      </ChartDefaults>
    </div>
  );
}
```

## A brand of your own

Set the tokens once in your global stylesheet, per mode. A scoped override (on a wrapper element)
reaches the charts inside it only. The full list and the rules are in the
[API reference](/packages/active-charts/api), § 13.
