Troubleshooting
Fixes for the common microcharts failures: unstyled charts, a chart invisible on a dark panel, a 'use client' error, the removed onPointFocus callback, an inert animate prop, a chart that won't fill its container, and serif labels.
Most issues trace back to one of a handful of causes. Each fix is below, with a link to the guide page that explains it in full.
Charts render with no color, no strokes, just plain shapes
The stylesheet isn't loaded. Every visual property comes from styles.css: color, stroke weight, label size, the whole
theme. Import it once:
import "@microcharts/react/styles.css";Without it a chart is still valid, accessible SVG: the markup and the accessible name are both there, with no styling applied. See Quickstart for where the import goes in your framework.
A chart is invisible (or nearly) on a colored or dark panel
Charts never paint their own background; they render transparent SVG. On a plain light or dark page you never notice,
because the built-in light and 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.
The tokens don't know that scope looks dark; they only know what the OS or 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 if you don't 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:
// ❌ 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? }, where value is the raw number and formatted
is the chart's ready-to-display string; it's null when the chart clears. onPointFocus on Sparkline and SparkBar and
StreakSpark's onRunFocus map across directly. 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. For 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 this to the console when the engine is missing. Three other reasons animate is 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, where
an entrance would animate content the reader can already see. The entrance 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. Interactive entries behave identically: 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, so 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
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
Where the size and speed numbers come from: 106 chart types at ~2–7 kB interactive · ~1–4 kB static, a static server render of about 0.03 ms each, and the commands that regenerate every figure.
Design notes
Why microcharts defaults the way it does — no axes or legends, static-first entries, one shared grammar, generated summaries, size budgets as CI gates, and the bar a new chart type has to clear.