Skip to content
microcharts
ReferenceCoreBullet

Bullet

React bullet chart — measured value against a target tick and qualitative bands. Tiny accessible SVG microchart; RSC-safe static or /interactive.

Bullet compares one measured value to a target, against a backdrop of qualitative bands (poor / okay / good). It answers "are we there yet?" in a single row — ideal for progress, SLAs, budgets, and quotas.

Bullet
interactive · 3.46 kB · static · 2.31 kB

Install

Import & usereact/bullet
import { Bullet } from "@microcharts/react/bullet";<Bullet value={72} target={80} bands={[50, 90]} title="Quota" />
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — progress to a goal, a value against a target, KPIs with thresholds.
  • Avoid for — trends over time (use Sparkline) or distributions.

Sizing

width and height are viewBox units that also set the rendered pixel box — a bullet reads best wide and short. Omit them and drive the width from CSS to fill a table cell or card column; the viewBox keeps the aspect ratio.

Variants

behind target
ahead of target
no bands

Edge cases

value beyond the domain
no data

Four homes

Why this default

The qualitative bands sit lowest and graduate in shade by step, because they are context, not the answer — the measure bar has to read as the loudest mark on the row. The target is a tick, not a second bar: a distinct shape at a distinct position so "value vs target" survives grayscale print and never depends on the two colors staying apart. The measure bar itself is a thin band centered in the track (Few's proportion, not a full-height fill) so the bands stay legible on both sides of it.

Accessibility

Bullet announces its value against its target — "72 of 80 target.". No color is required to read whether the target was met: the measure's length and the target tick encode it by position, and the qualitative bands sit behind them. The interactive entry reads the value and target on hover and focus.

This chart is a single unit, so there is nothing to rove between: a click, tap, Enter or Space selects it and fires onSelect, and no selection stays pinned. That is the scalar half of the shared interaction contract.

Props

PropTypeNotes
value*numberThe measured value.
targetnumberTarget tick to compare against.
bandsnumber[]Ascending qualitative thresholds.
domain[number, number]Explicit [0, max]; auto-fit otherwise.
label"none" | "value" | "target" | "both"Value/target readout in a right gutter (default none).
titlestringAccessible name; joins the auto summary.
summarystring | falseOverride or disable the auto 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