# Quickstart (/docs/quickstart)

## Set up

Prefer an agent — paste the prompt once. It installs the package, imports the stylesheet at your app root, records the
conventions in your agent-rules file, and verifies with a first chart. Or do the two steps yourself under
[Set up manually](#set-up-manually).

### Set up with an AI agent

Hand the prompt below to your coding agent — **Cursor, Claude Code, GitHub Copilot, Codex**, or any model, large or
small. Works on a fresh repo or an existing one. It's also served verbatim at [`/agent-setup.md`](/agent-setup.md).

<div className="agent-prompt">

```md title="Paste into your agent"
Set up **@microcharts/react** in this repo — word-sized, zero-dependency React charts (React 18 or 19 peer, ESM-only).
Complete every step in order; don't stop to ask.

## 1 · Install

- If this repo is not already a React 18/19 app, scaffold one first (Vite `react-ts` or Next.js), then continue.
- Install `@microcharts/react` with this repo's package manager.
- Import the stylesheet once at the app root (both package + stylesheet are required):
  - Next.js App Router: `app/layout.tsx`
  - Next.js Pages Router: `pages/_app.tsx`
  - Vite / other React apps: the entry file (e.g. `src/main.tsx`) `import "@microcharts/react/styles.css"`
- Charts inherit the page font. If labels look like a serif fallback, set `:root { --mc-font: system-ui, sans-serif; }`.

## 2 · Docs — fetch small, on demand

- https://microcharts.dev/llms.txt — index: every chart + guide links. Read this now.
- https://microcharts.dev/catalog.json — full API. Do **not** read the whole file. Find the chart by `slug`, then use
  `sharedProps` + that chart's `props`. If the chart has `sharedInteractive` / the document has `howToRead`, follow
  those; otherwise use the chart's `.md` for interactive callbacks. Never invent props.
- https://microcharts.dev/docs/charts/<slug>.md — one chart's page (import path, edge cases). Fetch only for charts you
  use — pick the slug from the index.
- https://microcharts.dev/docs/quickstart.md — grammar + interactive contract, if you need more than the rules below.

If you can't fetch URLs, skip this step — the rules below are enough to render a first chart correctly.

## 3 · Record the conventions

Append the rules below as a `## microcharts` section in `AGENTS.md` (create the file if missing — Cursor, Copilot, and
Codex read it). If this repo uses Claude Code, mirror it: `ln -s AGENTS.md CLAUDE.md` on macOS/Linux, or copy the
section into `CLAUDE.md` on Windows.

- One chart = one subpath import, e.g. `import { Sparkline } from "@microcharts/react/sparkline"`. The default export is
  static — RSC-safe, zero client JS. Add `/interactive` only when hover, keyboard, touch, or selection is needed. That
  entry is a client component: in Next.js App Router, import it from a `"use client"` file. WindBarb is static-only.
- `data` alone always renders; single-value charts take `value` instead. Shared prop names mean the same thing
  everywhere — see `sharedProps` in `/catalog.json`. Chart-specific props and callbacks live on the chart's catalog
  entry and its `.md` page; don't memorize them.
- Interactive entries share one contract: hover/arrows activate; click/tap/Enter/Space select; Escape clears. Prefer
  each chart's `sharedInteractive` list when present (lean scalars may take only `onSelect`; MinimapStrip uses
  `onWindowChange` in chart `props`). For entrance motion: pass `animate` and import `@microcharts/react/motion` once on
  the client.
- `null`, `NaN`, or non-finite values in `data` are gaps, never zeros.
- Accessibility is automatic (`role="img"` + a generated summary). Inline in a sentence: wrap in
  `<span className="mc-inline">` and pass `summary={false}`.
- Theme with `--mc-*` or `data-mc-theme` (omit for default), or `defineTheme` from `@microcharts/react/theme`. Charts
  paint no background. Prefer tokens; `color` / categorical `colors[]` are valid when the chart's docs say so.
- Annotations are children: `Threshold`, `TargetZone`, `Marker`, `Callout` from `@microcharts/react/annotations`.
- Never add another charting dependency. No pie or gauge — use `Bullet`, `SegmentedBar`, or `MicroDonut`.

## 4 · Verify

Render `<Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" />` in a real page, then run the dev server or
build. Self-check:

- Chart missing or unstyled → the styles.css import isn't at the root (step 1).
- Labels render in a serif font → set `--mc-font` (step 1).

Finish with a short report: the installed version, the file importing styles.css, the file holding the conventions, and
the page rendering the test chart.
```

<AgentPromptCopy />

</div>

The prompt fetches small, targeted files — the [`/llms.txt`](/llms.txt) index first, then one chart's `.md` page at a
time — so it stays inside the context window of smaller models and works from today's real API instead of a memorized
guess. The rules are inlined too, so it still works when the agent can't reach the network.

### Set up manually

Two steps, once, at your app root — package plus stylesheet. Both are required, and both fit in the next minute.

**1 · Install.** React 18 or 19 is a peer dependency; there are no other runtime dependencies.

**2 · Import the stylesheet once** at the root of your app — it carries every theming token and chart style in a
low-specificity cascade layer, so your own styles always win. Where "root" means depends on your framework — anywhere
that runs once, before any chart renders:

#### Next.js

```tsx title="app/layout.tsx"
import "@microcharts/react/styles.css";
```

#### Vite / CRA / other React apps

```tsx title="src/main.tsx"
import "@microcharts/react/styles.css";
```

> Charts **inherit your page's font**. If the surrounding page never sets a `font-family` (some minimal starters and sandboxes don't), SVG text falls back to a serif and labels look wrong — give your page a font, or set one just for charts: ```css :root { --mc-font: system-ui, sans-serif; } ``` Full detail — why it inherits, and per-scope fonting — in [Theming](/docs/theming#the-font).

## Your first chart

Every series chart renders from `data` alone — single-value charts take `value`. Either way it works in a React Server
Component with **zero client JavaScript** — it's pure SVG, and its accessible name is generated from the data.

```tsx
import { Sparkline } from "@microcharts/react/sparkline";

export default function Page() {
return <Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" />;
}
```

### Try it live

No install needed to feel it out. Open a full Vite + React app with the package installed in StackBlitz — static and
interactive charts, inline and block, four themes, running in your browser.

<StackBlitzSandbox />

## The shared grammar

One idea runs through the whole catalog: **the same prop name means the same thing on every chart.** Learn these once
and they transfer everywhere — a new chart type is a new data shape, never a new vocabulary. The data prop alone always
renders something correct; everything else is opt-in.

| Prop       | Type                                        | What it does                                                                                                                                    |
| ---------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `data`     | `(number \| null)[] \| per-chart shape`     | The series. `null` / `NaN` are gaps, never zeros. The one required prop; each chart documents its own shape when it isn't a plain number array. |
| `domain`   | `[min, max]`                                | Fix the value range instead of auto-fitting — see [Formatting & scale](/docs/formatting#scale-the-domain-decision).                             |
| `color`    | `string`                                    | Mark color: any CSS color or a token (`"var(--mc-accent)"`). Semantic tokens keep their meaning — see [Theming](/docs/theming).                 |
| `title`    | `string`                                    | Names the chart — an SVG `<title>`, so it becomes the accessible name and the hover tooltip, not visible text.                                  |
| `summary`  | `string \| false`                           | Override the auto-generated accessible sentence, or pass `false` to mark the chart decorative — see [Accessibility](/docs/accessibility).       |
| `format`   | `Intl.NumberFormatOptions \| (n) => string` | How numbers render in labels and summaries — see [Formatting & scale](/docs/formatting).                                                        |
| `positive` | `"up" \| "down"`                            | Which direction is good, so color and arrows point the honest way (lower latency is `"down"`).                                                  |
| `label`    | _per chart_                                 | A short direct label next to the mark, in a reserved gutter — never an axis or legend.                                                          |
| `dots`     | _per chart_                                 | Which individual points to emphasize (e.g. `"minmax"` on a line).                                                                               |

Not every prop applies to every chart — a bar chart has no `dots`, and the single-value charts take `value` rather than
`data` — but wherever a concept exists, its prop name and meaning are always these. Each one has a deeper home:
[Formatting & scale](/docs/formatting) owns `format` and `domain`, [Theming](/docs/theming) owns `color`, and
[Accessibility](/docs/accessibility) owns `summary`.

Alongside the grammar sit the layout props — `className` and `style` on every chart, plus `width` and `height` on the
charts whose geometry is sized that way (the fixed-glyph ones size from `style` or their own `size` / `cell` knob) and
`id`, which opts into `<title>`/`<desc>` + `aria-labelledby` naming; see [Sizing](/docs/sizing). The i18n props are
`locale` (BCP-47, for number and date formatting) and `strings` (the summary/label templates), plus `seriesStrings` on
the multi-series charts — see [Accessibility](/docs/accessibility#internationalization-and-rtl). Everything else is
specific to a chart's own shape and listed in the prop table on its page. To place charts in real UI — or render several
on one shared scale with `SparkGroup` — see [Composition](/docs/composition). Annotations are children:
[`Threshold`, `TargetZone`, `Marker`, `Callout`](/docs/annotations).

## Add interactivity

Need hover, keyboard navigation, touch, or live announcements? Import the same chart from its `/interactive` entry. The
rendered output and the accessible name are identical — the interactive entry composes its static twin rather than
re-implementing it — and it **adds** props rather than changing any: the interaction callbacks below, plus `animate`,
`strings` on the charts whose static entry doesn't take it, `live` on the single-value charts, and `onWindowChange` on
MinimapStrip. The interactive entry **is** a client component: in a Next.js App Router page, render it from a file with
`"use client"` at the top (or anywhere inside one).

```tsx
"use client";

import { Sparkline } from "@microcharts/react/sparkline/interactive";

<Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" />;
```

### One interaction contract

Every interactive chart behaves the same way, so you learn it once. Hover or arrow keys make a unit **active**; a click,
tap, **Enter**, or **Space** **selects** it and pins the readout so it survives blur. **Escape** clears,
**Home**/**End** jump to the ends, and arrows rove in both axes (←/↑ previous, →/↓ next). On touch, a tap pins and a
drag scrubs. What a "unit" is depends on the chart — a point, a bar, a day cell, a segment — and each chart's page names
its own.

| Prop                   | Type                                  | What it does                                                                         |
| ---------------------- | ------------------------------------- | ------------------------------------------------------------------------------------ |
| `onActive`             | `(datum: MicroDatum \| null) => void` | The active unit changed (pointer or keyboard). `null` when the chart clears.         |
| `onSelect`             | `(datum: MicroDatum \| null) => void` | A unit was selected or unselected — click, tap, `Enter`, `Space`, `Escape`.          |
| `selectedIndex`        | `number \| null`                      | Control the selection yourself.                                                      |
| `defaultSelectedIndex` | `number \| null`                      | Seed the selection once, then let the chart own it.                                  |
| `readout`              | `boolean`                             | Show the floating value chip on hover (default `true`). `false` hides only the chip. |

`MicroDatum` is `{ index, value, label?, formatted? }`. Two of the fields carry the value in different forms, so you
pick the one that fits: **`value`** is the raw primary number — compute with it (`null` when the unit encodes nothing);
**`formatted`** is the ready-to-display string the chart's own readout would show, built with your `format`/`locale` —
render it. For a plain chart that's just the value (`"$0.53"`); for a two-part unit it's the whole readout
(`"48 → 68 (up 42%)"`). `index` identifies the unit (point, bar, cell, segment…), and `label` is its human name where
one exists (`"Berlin"`, `"Checkout"`). Same shape on every chart and both callbacks.

Pair the two to lift the value out of the chart. Set `readout={false}` to keep the hover crosshair but suppress the
in-chart chip, and read `datum.formatted` in `onActive` to render that value wherever you like — a KPI number, a
sentence, a table cell — without re-deriving `format`/`locale` yourself:

```tsx
const [spend, setSpend] = useState("$0.53");
<Sparkline data={cost} format="$,.2f" readout={false} onActive={(d) => d && setSpend(d.formatted!)} />;
```

Scalar charts with a single unit — Delta, Progress, StatusDot, Bullet and the rest — take `onSelect` only; there's
nothing to rove between. Fifteen of them also take `live` (default `true`): as the value updates, the new reading is
announced through a polite live region, throttled so a streaming number never spams a screen reader. Not all of them do
— Bullet's only interaction prop is `onSelect` — so check the chart's own page. Two charts opt out of the picker on
purpose: `MinimapStrip` is a range slider with its own `onWindowChange([lo, hi])`, and `TokenConfidence` moves real
focus through inline text spans. Full detail, including the live-region behavior, is on
[Accessibility](/docs/accessibility#one-interaction-contract).

## Animate on mount (optional)

Interactive entries also take an `animate` prop — the chart draws on instead of appearing instantly. It's off by
default, and inert on the server and on hydrated server HTML, so it never fights SSR or flashes over painted content; a
fresh client-side mount is what plays it. Wire the engine once, client-side, then opt in per chart:

```tsx
"use client";

import "@microcharts/react/motion"; // once, client-side
import { Sparkline } from "@microcharts/react/sparkline/interactive";

<Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" animate />;
```

`prefers-reduced-motion` wins unconditionally — a reader who asked for less motion gets the finished chart, never the
entrance.

## Import paths

Import each chart from its own subpath so you only ship what you use. Nearly every chart follows the same two-entry
pattern — a static default and an `/interactive` twin (WindBarb is the lone static-only exception):

| Chart        | Static                             | Interactive                                    |
| ------------ | ---------------------------------- | ---------------------------------------------- |
| Sparkline    | `@microcharts/react/sparkline`     | `@microcharts/react/sparkline/interactive`     |
| SparkBar     | `@microcharts/react/sparkbar`      | `@microcharts/react/sparkbar/interactive`      |
| Delta        | `@microcharts/react/delta`         | `@microcharts/react/delta/interactive`         |
| Bullet       | `@microcharts/react/bullet`        | `@microcharts/react/bullet/interactive`        |
| ActivityGrid | `@microcharts/react/activity-grid` | `@microcharts/react/activity-grid/interactive` |

Every other chart uses the same shape (WindBarb ships static-only, with no `/interactive` twin) — see
[All charts](/docs/charts) for the full catalog, each page listing its own import path and props.

## Compatibility

- **React 18 or 19** as a peer dependency — no other runtime dependencies, ever (`dependencies: {}`, CI-enforced).
- **ESM-only.** The package ships `"type": "module"`; there's no CommonJS build.
- **Server-component and SSR-safe.** Static entries are hook-free and listener-free, so they render to plain SVG on the
  server with zero client JavaScript — no `"use client"` needed unless you import from `/interactive`.
- **Browser floor: evergreen, ES2022.** That includes Safari from version 16.4 — a couple of ES2022 array methods used
  internally crash on older Safari, so that's the practical minimum, not just a `tsconfig` setting.
