Skip to content

Getting started ​

Install ​

@adecore/ui, React 19, react-dom, i18next and react-i18next are peer dependencies:

sh
bun add @adecore/charts @adecore/ui i18next react-i18next

d3-scale and d3-shape come with the package. Set up @adecore/ui first. The charts draw on its theme and write their numbers and dates with its formatters, so they follow the format source UIProvider hands over.

Load the styles ​

The package ships no stylesheet of its own. Its parts use Tailwind classes on the tokens of the theme, so let Tailwind scan it next to @adecore/ui:

css
@import "tailwindcss";
@import "@adecore/ui/theme.css";
@source "../node_modules/@adecore/ui/dist";
@source "../node_modules/@adecore/charts/dist";

The @source paths are relative to the CSS file.

Add the words ​

The words ("No data", "Show values") live in a charts namespace, in English and Dutch. Add them to the app's i18next:

ts
import { CHARTS_NAMESPACE, CHARTS_RESOURCES } from '@adecore/charts';

for (const [language, words] of Object.entries(CHARTS_RESOURCES)) {
    i18n.addResourceBundle(language, CHARTS_NAMESPACE, words);
}

Colors ​

A series takes a tone: a status tone of the theme (accent, error, needsYou, idle, running, muted) or { color } with any CSS value, such as { color: 'var(--brand)' }. The type is ChartColor; the status tones alone are a ChartTone.

Without a tone, the series take --chart-1 to --chart-6 in order. That palette lives in the theme of @adecore/ui, not in this package. --chart-1 is the accent, so the first series follows the accent the app sets.

A first chart ​

Tokens per day, input and output stacked:

tsx
import { createChart } from '@adecore/charts';
import { formatDay, formatTokens } from '@adecore/ui/format';
import { tokensPerDay, type TokenDay } from '../shared/chart-data.ts';

const UsageChart = createChart<TokenDay>();
const days = tokensPerDay();

export default function TokensPerDayDemo() {
    return (
        <UsageChart.Root data={days} x="day" label="Tokens per day" height={220} className="w-full">
            <UsageChart.Grid />
            <UsageChart.YAxis format={formatTokens} />
            <UsageChart.XAxis format={(day) => formatDay(day as number)} />
            <UsageChart.Bars stack>
                <UsageChart.Bar value="input" label="Input" />
                <UsageChart.Bar value="output" label="Output" />
            </UsageChart.Bars>
            <UsageChart.Tooltip total />
            <UsageChart.Legend />
        </UsageChart.Root>
    );
}
tsx
import { createChart } from '@adecore/charts';
import { formatDay, formatTokens } from '@adecore/ui/format';

interface TokenDay {
    day: number;
    input: number;
    output: number;
}

const UsageChart = createChart<TokenDay>();

export function TokensPerDay({ days }: { days: TokenDay[] }) {
    return (
        <UsageChart.Root data={days} x="day" label="Tokens per day" height={220}>
            <UsageChart.Grid />
            <UsageChart.YAxis format={formatTokens} />
            <UsageChart.XAxis format={(day) => formatDay(day as number)} />
            <UsageChart.Bars stack>
                <UsageChart.Bar value="input" label="Input" />
                <UsageChart.Bar value="output" label="Output" />
            </UsageChart.Bars>
            <UsageChart.Tooltip total />
            <UsageChart.Legend />
        </UsageChart.Root>
    );
}

Chart.Root owns the data, the scales, the cursor and the keyboard. Each part inside it draws one layer, in the order of the children, so the grid goes first. Chart.Tooltip, Chart.Legend and Chart.Table take their own places whatever their order. The reference lists every part.

The width follows the container, and height is fixed. label is required. A screen reader reads it as the name of the chart, and the table shows it as its caption.

Typed rows ​

JSX cannot check value="input" against the row type. createChart<Row>() returns Chart typed as a TypedChart, so x, group and value take only keys or accessors of Row. The plain Chart takes any key, and warns in development when the first row lacks it:

tsx
import { Chart } from '@adecore/charts';

<Chart.Root data={days} x="day" label="Tokens per day">
    <Chart.Bar value="input" label="Input" />
</Chart.Root>

Checklist ​

  • @adecore/ui is set up, with UIProvider above the charts.
  • Tailwind scans @adecore/charts next to @adecore/ui.
  • The charts namespace is in the app's i18next.
  • Every chart has a label.
  • The parent gives the chart its width, and height sets its height.

Licenses and third-party notices are listed in each package.