Troubleshooting
The predictable failures — unstyled charts, a chart invisible on a dark panel, a 'use client' error from the /interactive entry, the removed onPointFocus callback, an animate prop that does nothing, a chart that won't fill its container, and fonts that look wrong — each with its one-line fix.
Most issues trace back to one of a handful of causes. This page is the fast path to each fix; the full explanation for each one lives on its own guide page, linked below.
Charts render with no color, no strokes, just plain shapes
The stylesheet isn't loaded. Every visual property — color, stroke weight, label size, the whole theme — comes from
styles.css, imported once:
import "@microcharts/react/styles.css";Without it, a chart is still valid, accessible SVG (the markup and the accessible name are both there), it just has no styling applied — geometry with no ink. See Quickstart for where to put the import in your framework.
A chart is invisible (or nearly) on a colored or dark panel
Charts never paint their own background — they're transparent SVG, always. On a plain light or dark page this is
invisible because the built-in light/dark tokens track prefers-color-scheme. It breaks when a chart sits on a surface
whose color doesn't match the page's color scheme — a dark-branded card on an otherwise light page, or a colored KPI
tile — because the tokens don't know that scope looks dark; they only know what the OS/browser reports.
Fix it by rebinding the token scope to match the surface, not the page:
.dark-panel {
--mc-stroke: #f5f5f5; /* text + data strokes; add --mc-neutral for muted labels */
}or force the whole preset for that scope:
<div data-mc-theme="dark">
<Sparkline data={data} />
</div>See Theming for the full token set and how scope, preset, and prop precedence works.
Error: ... 'use client' ... when importing a chart
You imported a chart's /interactive entry into a Server Component:
// ❌ interactive entries are client components — this throws in an RSC
import { Sparkline } from "@microcharts/react/sparkline/interactive";Two ways out: render the static default entry instead if you don't actually need hover, keyboard, touch, or selection —
import { Sparkline } from "@microcharts/react/sparkline";— or, if you do need interactivity, move the import into a component marked "use client" and render that component
from your server tree. See Quickstart for the static-vs-interactive split.
onPointFocus / onRunFocus no longer fire
They were removed when every interactive chart moved onto one shared contract. The replacement is onActive, which
fires for the same reason on every chart in the catalog rather than under a different name per chart:
// ❌ removed
<Sparkline data={data} onPointFocus={(i) => setHovered(i)} />
// ✅ one name, everywhere
<Sparkline data={data} onActive={(d) => setHovered(d?.index ?? null)} />The payload is a MicroDatum — { index, value, label?, formatted? } (value is the raw number, formatted the
chart's ready-to-display string) — or null when the chart clears. onPointFocus on Sparkline and SparkBar and
StreakSpark's onRunFocus map across directly. Note that index identifies the chart's navigable unit, which isn't
always a series index: on Waveform it's a bucket, on Hypnogram a run, on SegmentedBar a segment. Each chart's page names
its own unit. If you also want click-to-pin, add onSelect — see
Accessibility.
animate does nothing
The entrance engine isn't loaded. animate is a flag; the code that runs the animation ships in a separate side-effect
import you add once, anywhere in your client bundle:
import "@microcharts/react/motion";In development the chart logs exactly this to the console when the engine is missing. Three other reasons animate is
correctly inert, none of them bugs: the reader has prefers-reduced-motion: reduce, the chart is a static entry
(animate is an /interactive-only prop), or the markup came from the server and is being hydrated rather than freshly
mounted — an entrance would mean animating content the reader can already see. The entrance also runs once per mount by
design; remount with a changed key to replay it.
The chart won't stretch to fill its container
.mc-root — the chart's own <svg> — is display: inline-block by default, so it flows next to text instead of
stretching. Give it fluid sizing explicitly:
<Sparkline data={data} style={{ width: "100%", height: "auto" }} />and make sure the parent is block-level (a flex or grid item, or a div) — a chart can't grow past an inline parent
no matter what you set on the chart itself. This is identical for …/interactive entries: style, className, and
width/height size an interactive chart exactly the way they size its static twin, and hit-testing stays exact at any
size — the crosshair tracks the cursor and a touch drag scrubs the unit under the finger. Full recipes, including the
inline-in-a-sentence case, are on Sizing & scaling.
A chart stacks on its own line instead of sitting inline with text
This is usually a CSS reset, not a microcharts bug. .mc-root's display: inline-block is declared inside a
zero-specificity :where() so your styles always win — including ones you didn't mean to apply. Tailwind's Preflight
sets a plain svg { display: block; ... } rule, which has higher specificity than any :where() selector and so
overrides it, dropping the chart onto its own block-level line. Re-assert the layout you want at the call site:
<Sparkline data={data} className="inline-block" />or wrap it in className="mc-inline" for text-flow placement — see
Sizing & scaling.
Chart labels look wrong — a serif fallback, or mismatched with the page
Charts inherit font-family from the page; they don't set one of their own. If the surrounding page never declares a
font (a bare sandbox, a minimal starter), SVG text falls back to the browser's default serif. See
Theming → The font for why it inherits and how to set it per-scope.
Performance
Zero dependencies, budget-gated sizes, and server rendering with no client JavaScript — 106 chart types at ~2–7 kB interactive · ~1–4 kB static, static SSR median about 0.03 ms each. Every number here is reproducible from one command.
Design notes
The reasoning behind microcharts' defaults — direct labels over chrome, static-first architecture, one grammar, summaries as a first-class feature, budgets as build gates, and a strict bar for admitting a new chart type.