microcharts
Renders word-sized charts — sparklines, bars, bullets and 100+ more types — to self-contained SVG with generated alt text, small enough to sit inline in a model's reply or a table cell. Three tools: find the right chart for a question, get its wiring, and render it.
README
<div align="center">
<img src="assets/promo.png" alt="microcharts — word-sized charts for React, made for AI first and for the people reading what it writes. 106 chart types, zero dependencies, ~2–7 kB interactive · ~1–4 kB static." width="920">
@microcharts/react
Word-sized charts for React — zero runtime dependencies, ~2–7 kB interactive · ~1–4 kB static, accessible by default, and server-component safe.
<br>
Docs · Gallery · Quickstart · AI usage · llms.txt
</div>
microcharts is 106 tiny, handcrafted chart types built to sit inside an interface — in a sentence, a table cell, a KPI card, a tab header, a streamed AI reply — where a full chart library would be too heavy and too loud. One quiet signal, read at a glance.
The grammar is small enough for a model to emit correctly mid-sentence, and every chart describes itself in words. So a chart an LLM streams into a chat reply is one a person can read and trust — the properties that make it safe for a model to write are the ones that make it pleasant for a human to use.
Status: production-ready, still earning its scars. microcharts is tested and ready to use in production, but it hasn't been battle-tested across every stack and edge yet — you may hit the occasional rough edge. When you do, tell us: bug reports and feature requests on GitHub issues are how it keeps getting sharper.
Why
- AI-native. A chart is plain
dataplus a generated sentence. One grammar across all 106 types — a model that has seen one chart can write them all. → AI usage - Zero dependencies. No chart engine, no D3 — just SVG. React is the only peer. CI-enforced, forever.
- Server-component safe. Static charts are hook-free and render to HTML with zero client JavaScript.
Interactivity is a separate opt-in
/interactiveimport. - Accessible by default. Every chart is an
imgwith a natural-language summary built from your data — nothing to remember, nothing to drift. → Accessibility - Tiny + honest. ~2–7 kB interactive · ~1–4 kB static gzip per chart, budget-gated in CI. Every type has one documented, honest encoding channel. Delight never lies.
Install
npm install @microcharts/react
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:
// app/layout.tsx
import "@microcharts/react/styles.css";
Your first chart
Every chart renders from data alone. This works in a React Server Component with zero client JavaScript — pure
SVG, and its accessible name is generated from the data.
import { Sparkline } from "@microcharts/react/sparkline";
<Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" />;
Each chart imports 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).
Add interactivity
Need hover, keyboard navigation, touch, or live announcements? Import the same chart from /interactive. The rendered
output and the accessible name are identical — the interactive entry composes its static twin — and it adds props
rather than changing any: you opt into the client component where it matters.
import { Sparkline } from "@microcharts/react/sparkline/interactive";
<Sparkline data={[3, 5, 4, 8, 6, 9]} title="Weekly revenue" />;
Every interactive chart shares one contract, so you learn it once. Hover or arrow keys make a unit active; a click,
tap, <kbd>Enter</kbd>, or <kbd>Space</kbd> selects it and pins the readout so it survives blur; <kbd>Escape</kbd>
clears; <kbd>Home</kbd>/<kbd>End</kbd> jump to the ends. Read it back with onActive and onSelect — payload
{ index, value, label?, formatted? }, where value is the raw number and formatted is the chart's ready-to-display
string — and control the pin with selectedIndex / defaultSelectedIndex. Set readout={false} to hide the in-chart
value chip and render datum.formatted wherever you like. Single-unit scalar charts (Delta, Progress, StatusDot,
Bullet, …) take onSelect alone.
<Sparkline data={[3, 5, 4, 8, 6, 9]} onActive={(d) => setHovered(d?.value ?? null)} onSelect={(d) => pin(d)} />
Annotate with children
Thresholds, markers, and target zones are children — the same grammar on every chart that supports them:
import { Sparkline } from "@microcharts/react/sparkline";
import { Threshold, Marker } from "@microcharts/react/annotations";
<Sparkline data={[120, 180, 240, 210, 260]} title="Latency p95">
<Threshold y={200} label="SLO" />
<Marker x={2} celebrate />
</Sparkline>;
Theme it
About two dozen --mc-* CSS custom properties are the runtime contract; presets are token bundles. Set one on a subtree
with the provider — presets are visual only and never change what the data means:
import { MicroProvider } from "@microcharts/react";
<MicroProvider theme="editorial">
<Sparkline data={[3, 5, 4, 8, 6, 9]} />
</MicroProvider>;
Presets: modern (default), editorial, mono, vivid, plus output-context print and eink. Dark mode is
hand-tuned, not inverted. For a whole brand theme, defineTheme (from @microcharts/react/theme) derives a matched,
colour-blind-safe palette and dark twins from one accent:
import { defineTheme } from "@microcharts/react/theme";
const brand = defineTheme({ accent: "#6d28d9" });
<MicroProvider style={brand.style}>…</MicroProvider>;
Retune density with one scalar (--mc-density), give figures their own face (--mc-font-numeric), or recolour a single
categorical chart with a colors array. → Theming guide
The catalog
106 stable chart types — 34 core, 26 decision, 23 expressive, 23 frontier — grouped by the question each one
answers. data alone always renders something correct, and a prop name means the same thing on every chart (domain,
color, title, summary, label, format…), so you pick by the decision you need read, not by fighting an options
bag.
Sparklines, bars, deltas, and bullets through bump charts, funnels, honeycombs, calendar strips, and confidence bands — browse them all in the live gallery →
Not shipping, on purpose: pie, needle-gauge/speedometer, battery, waffle, violin. Each fails at micro scale or on the honest-encoding bar, and each has a strictly-better in-catalog replacement (Bullet for gauges, SegmentedBar for pie, MicroBox for violin). → what to use instead
Made for models
microcharts is built to be written by an LLM and read by a person. The docs site publishes machine surfaces alongside the human ones:
| Surface | What it is |
|---|---|
/llms.txt |
Curated map of the catalog and guides |
/llms-full.txt |
The complete generated docs corpus |
/catalog.json |
Every chart's name, import path, props, data shapes |
Call it over MCP
Those surfaces are for a model that reads. @microcharts/mcp is for
one that calls — a Model Context Protocol server that runs on your machine over stdio, with three tools backed by this
library: find the chart type that answers a question, get its exact props and a ready-to-render sample, and
render it to a self-contained SVG with the generated alt text attached.
{
"mcpServers": {
"microcharts": {
"command": "npx",
"args": ["-y", "@microcharts/mcp"]
}
}
}
Works in Claude Desktop, Claude Code, Cursor, and VS Code; nothing is hosted and no key is involved. The same three
capabilities ship as Vercel AI SDK tools on the @microcharts/mcp/ai-sdk subpath. Full reference:
microcharts.dev/docs/mcp. Also listed in the
Glama MCP registry.
Compatibility
React 18 and 19. ESM-only, per-component subpath exports, types-first export conditions. Static charts render in any RSC or SSR setup with no client runtime.
sideEffects is a two-entry allowlist rather than false, because styles.css and the opt-in ./motion engine are
both imported for their side effects and false would let a bundler drop them. Every other module is side-effect free
and tree-shakes normally — and since charts ship as per-component subpaths, you only ever pay for the ones you import.
Contributing
pnpm install
pnpm check # typecheck + lint + format + test + knip
pnpm size # gzip budgets (needs a build first)
pnpm build
See CONTRIBUTING.md. Issues and ideas welcome — new chart types are held to a high bar (≤ 200×60 px, a unique data story, an honest channel, readable without training).
License
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.