Skip to content
microcharts
ReferenceCoreSparkBar

SparkBar

SparkBar renders discrete values as zero-anchored bars, or a win–loss–tie streak in winloss mode.

encodes
length (bar height from a zero baseline)
precision
high
nodes
1 per bar
collection
Core
Source

SparkBar renders discrete values as compact bars from a zero baseline: one bar per period, always anchored at zero, because a bar that starts anywhere else misstates its magnitude. Each period is its own count — a deploy total, a daily total — rather than a sample on a continuous curve. In bar mode the endpoint bar takes the accent, since "where did it land" is usually the first question a run of counts answers.

winloss mode discards magnitude on purpose and collapses each value to its sign: wins above the mid-line, losses below, and a tie (0) as a thin neutral dash on it. There every bar keeps its own win/loss/tie color, endpoint included, because the sign is what matters at each position. Sign is doubled by position and color wherever signed data appears, so direction survives forced-colors.

SparkBar
interactive · 6.01 kB · static · 3.37 kB

Install

Import & usereact/sparkbar
import { SparkBar } from "@microcharts/react/sparkbar";<SparkBar data={[4, 6, 2, 8, 5, 9]} title="Deploys per day" />
Needs package + stylesheetSet up with AI

Try it

Live playground
onActive
idle
  1. hover · rove · click…

Hover a bar, or focus and step through with ← →.

mode
label
positive
gap · 0.25
locale
readout
animate
import { SparkBar } from "@microcharts/react/sparkbar/interactive";<SparkBar  data={[4, 6, 2, 8, 5, 9, 3, 7, 6, 10]}  mode="bar"/>

When to use it

Use it for discrete magnitudes, win–loss streaks, and period-over-period counts. For a continuous trend shape use Sparkline, which is also the better choice at hundreds of points, where bars become noise.

Sizing

width and height are viewBox units that also set the rendered pixel box. Omit them and drive the width from CSS for a chart that fills its container — the viewBox keeps the aspect ratio.

default
fixed size
responsive

Where the plot floor sits

In bar mode the bars stand on the bottom edge of the viewBox. There is no bottom padding, so a bar's foot and the box bottom are the same line. That is what seats the chart on the text baseline when it sits inline. Draw your own rule or divider below the box rather than flush with it, or it covers the bar feet by a pixel or two. winloss mode insets its bottom edge instead, because a mid-line streak has no floor to stand on.

Variants

bar (default)
winloss
winloss with ties
label
locale

The endpoint label and accessible summary both follow format/locale: 8600 reads "8.600" under de-DE rather than the English "8,600".

Edge cases

empty data
single bar

An empty series renders no bars and an accessible name that says so, rather than a flat or invented baseline. A single value still renders as one zero-anchored bar, and winloss mode treats it the same way a longer streak would: a lone win, loss, or tie.

zeros and gaps

A zero paints no bar. Bar length encodes magnitude, and zero magnitude is zero length, so the slot keeps its place on the pitch and stays empty. A period you have no reading for takes null, which occupies no slot at all. Pass the real zero rather than substituting null for it: the generated summary counts a zero in the range and skips a gap, and the interactive entry reads a zero as "0" where it reads a gap as "no data". In winloss mode a 0 is a tie instead — a state rather than a magnitude — so it keeps its dash on the mid-line.

Name the bars

The interactive entry takes labels, indexed like data. The hover readout then names the period it shows instead of only its value, and the live region announces the name ahead of the position:

import { SparkBar } from "@microcharts/react/sparkbar/interactive";

<SparkBar data={mrr} labels={["Jun 2026", "Jul 2026", "Aug 2026"]} />;

The chip reads Aug 2026 · 1.1K, and the announcement reads "Aug 2026. Point 3 of 12: 1.1K." The name also arrives on onActive and onSelect as datum.label, so a host that renders its own readout gets it without a second lookup.

A hole in the array, or an empty string, leaves that one bar on the positional wording. Both joins are localizable through the named and namedChip string templates. The static entry ignores labels: it has no readout to name, and the generated summary stays value-based.

Four homes

In a sentence

Deploys peaked at nine mid-week — quieter since.

In a table cell
checkout13
search10
billing2
In a KPI card
CI pass rate
5 / 7last 7 runs
In a tab header
CIRelease

Preview uses the public chart API only. When an interactive twin exists, it swaps in with the same props and no entrance motion - code samples stay on the static import. Placement recipes: Composition, Sizing.

Accessibility

The accessible name is generated from the data. The example above reads:

Deploys per day. Trending up 125%. Range 2 to 9. Last value 9.

Sign is doubled by position (above or below the baseline), never by color alone, so the chart survives forced-colors and color-blind viewing.

The interactive entry follows the shared interaction contract: arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or Space selects a unit — pinning its readout so it survives blur, until you select it again, press Escape, or press outside the chart. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*number[]Values; negatives dip below the baseline.
mode"bar" | "winloss"Magnitude bars, or a win/loss/tie streak (sign only).
gapnumberEmpty fraction of each slot (0–0.9).
label"none" | "last"Direct endpoint value label.
positive"up" | "down""up" (default); "down" flips which sign is good.
labels(string | undefined)[]interactiveNames for the bars, indexed like `data`; the readout shows them.
titlestringAccessible name; joins the auto summary.
summarystring | falseOverride or disable the auto summary.
localestring | string[]BCP 47 locale(s) for the endpoint label and summary.
animatebooleaninteractiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion.

Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.

Related charts