Skip to content

Charts that fit in a sentence.

It’s small in the bundle too: the median chart is 5.24 kB and the biggest is < 7 kB.

There are 106 of them in four collections, the largest being the 34 in core.

Seven example apps ship with it and between them they use all 106 types.

On the page it stays just as light and the median one draws 1,375 bytes of SVG.

  • 2.18 kB
  • 0 dependencies
  • role="img"
  • arrow keys, one tab stop
  • name generated from data

The chart up there is a React component. Pass it an array and that’s the whole setup.

Set up with AI

The same sparkline in four places.

in a line of prose

Latency held under budget all week and finished at 141 ms.

in a table cell
routep957d
/checkout141
/search318
on a KPI card
p95 latency
141 ms
in a printed report

Checkout latency held at 141 msCheckout p95 latency, weekly, millisecondsthrough the release window.

static entry · no hover on paper · ink re-derived for the stock

A reader shouldn’t have to leave the sentence to understand the number. Here are thirteen weeks of bookings as a lineBookings by week, as barsBookings by weekand as a spreadSpread of weekly bookings— the same components the rest of this page uses, set like words.

three components, rendered on the server · no JavaScript, no images
1

All 106 work the same way.

Pass data and you get something correct. After that, domain, color and title mean the same thing in every chart. The catalog is typed, so an editor or an agent completes it without guessing.

one array, five types
const weeks = [128, 131, 129, 138, 141, 139, 148, 152, 150, 157, 161, 163]
<Sparkline data={weeks} />
<SparkBar data={weeks} />
<HeatStrip data={weeks} />
<RugStrip data={weeks} />
<MicroBox data={weeks} />

Inside a chart fence a model is only writing text. Close the fence and what you get back is the component you shipped.

Bookings recovered through November and closed the quarter ahead of plan.

```chart
{ "type": "sparkline", "data": [128, 131, 129, 138, 141, 139, 148, 152, 150, 157, 161, 163] }
```
renders as
llms.txtcatalog.jsonagent-setup.md
Sparkline
A trend over ordered values, small enough to sit in a sentence. position (length along a line), high precision.

Pie charts, needle gauges, violins and waffles stop being readable at this size, so the catalog doesn’t have them. Each one has a replacement that answers the same question.

same five shares · 28 24 19 16 13
Pie, 14pxWhich share is largest? You can’t tell.
SegmentedBar, 14pxThe first one, at 28%. Same size, same data.
needle gaugeBulletviolinMicroBoxbatteryProgresswaffleIconArray

Somewhere around 200 pixels a chart starts wanting axes, and that’s where you want a full charting library instead.

How big is it?

Recharts is a toolkit and 106 kB is a fair price for what it carries: tree-shaking drops the chart types you don’t use, but the shared kernel comes along either way. That’s a fine trade on a page that is mostly chart. In a table cell it’s the whole budget.

5 kB
101 kB you don’t ship

2.186.94 kB gzip per interactive chart. Median 5.24. Enforced in CI.

Static charts render in a Server Component and hydrate nothing. 0 kB of client JS.

recharts 3.9.2 one-chart esbuild tree-shake, 2026-07 · microcharts median from .size-limit.json · the CI run that produced it

dependencies: {}React is a peer dependency. There’s nothing else to install.

what you give up
measuremicrochartsa general-purpose toolkit
axes and gridlinesnonefull, configurable
tooltipsvalue readout on focusrich HTML, positioned
legendsnone — the sentence carries itbuilt in
chart types106, one shared API~15 composable primitives
works up toroughly 200 px300 px and up
cost per chart2.18–6.94 kB gzip106 kB shared kernel
static render0 kB of client JSclient-only

If you need axes and a legend, use a toolkit. Recharts is a good one.

Bad data renders anyway.

A model mid-reply will send NaN, or an empty array, or a single number. All three render something sensible, and nothing on this page is wrapped in try/catch.

[NaN, 3, Infinity]
One finite value, drawn as a point.
[]
Nothing drawn. It won’t invent a zero.
[-4, -4]
Flat at −4, on its own baseline.

The alt text writes itself.

It comes from the numbers the chart already has, so it can’t go stale: Trending up 27%. Range 128 to 163. Last value 163. The rest of the accessibility work is done too: one tab stop per chart, arrow keys to move between values, and nothing shown by color alone. Forced colors and RTL are handled.

← this one, named by that sentence

A theme starts with one color.

Give defineTheme an accent and it works out the rest: a color-blind-safe scale, and a dark version tuned by hand. Green stays positive and vermillion stays negative whatever you pass. Pick one below and watch the page take it.

accent
chart style

The default — nothing to override.

defineTheme({ accent: "#2f52d4" })
Bookings by week, drawn in the accent
--mc-accentThe color you pass. Emphasis marks take it.
Week-over-week change, up or down
--mc-positive --mc-negativeValence holds. No accent reaches these two.
Five shares of a whole
--mc-cat-1…6Six categories, derived from that one color.
Spread of weekly bookings
--mc-stroke --mc-stroke-widthDefault ink and weight. A style retunes both.

both controls write two attributes on <html> · every mark above follows · the whole token contract

Put a chart in a sentence.