Theming
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.
@workspace/active-charts 6.0.0Status unknowncontent differs from the recorded release 6.0.0baseline ce081dc3
A chart has no theme prop and no provider for colour. It reads CSS custom properties from the page:
- Chart tokens:
--chart-1to--chart-10for series,--chart-positive,--chart-negativeand--chart-cautionfor meaning,--chart-sequential-*and--chart-diverging-*for scales,--chart-on-fill-lightand--chart-on-fill-darkfor 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.
Every chart familyClient
// 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, § 13.