# BulletChart A measure, its target, and the bands that say whether it is any good. - Group: Data - Import: `import { BulletChart } from '@misoto22/design/charts'` - Page: https://ui.misoto22.com/components/bullet-chart/ - Related: bar-list, big-number ## When to reach for it A status page of ten tracked numbers. Stephen Few designed it to replace the dashboard gauge, which spends a whole card saying one number badly. ## Accessibility - Plain HTML with logical properties — no rendering engine, server-renderable, and correct in a right-to-left document. Usable with recharts absent. - The bands are a JUDGEMENT drawn in the same ink as the measurement, so the page has to say where they came from. Ranges that encode nothing but thirds make the chart look evaluated when it is not. - It shows one instant and no change over time; target is the only comparison it carries. “How did we get here” wants a LineChart. - Shared bands only mean something when the measures share a scale — a latency beside a conversion rate needs ranges and domain per measure. ## BulletChart A measure, its target, and the bands that say whether the number is any good — one dense row per thing being tracked. Stephen Few designed this to replace the dashboard gauge, and the argument has held: a speedometer spends a whole card saying one number badly, where a bullet graph says the same number, its target, and the qualitative context around it in the height of a line of text. Ten of them stack into a status page a reader can scan in one pass. What it will not do is show change over time. A bullet graph is one instant, and `target` is the only comparison it carries; when the question is "how did we get here" it wants a ``, and when several measures have to be compared against each OTHER rather than each against its own target, a `` ranks them and this does not. **The bands are the part to be careful with.** They are a judgement — someone decided that 80 is "good" — drawn in the same ink as the measurement, and a reader has no way to tell an agreed threshold from a number somebody typed. They also compress: a value near the top of the scale sits in the same band whether it cleared the boundary by a point or by thirty. The band answers "is this acceptable", never "by how much". No rendering engine, deliberately — this is the one chart in the set with nothing to compute. Each row is a single linear scale with no axis, no ticks and no shared plot area, so it is laid out as HTML: the bands and the bar are inline-axis offsets, which means the whole chart mirrors correctly in a right-to-left document, where an SVG drawn in user space would not. ### Props - `title` (required) — `string`. What the chart shows, in a sentence a reader could act on. Required, and announced to a screen reader even when it is not printed. - `showTitle` — `boolean`. Prints the title above the rows instead of hiding it from sight. - `description` — `ReactNode`. A line under the title — the unit, the window, the caveat. - `data` (required) — `BulletMeasure[]`. One entry per measure. Order is the reading order; it is not sorted. - `ranges` — `number[]`. The bands every measure falls back to, as ascending upper bounds. Shared bands only mean something when the measures share a scale. Where they do not — a latency beside a conversion rate — put `ranges` and `domain` on each measure instead. - `domain` — `[number, number]`. The scale every measure falls back to, as `[min, max]`. - `formatValue` — `(value: number) => string` default `defaultTick`. Formats every number the chart prints. - `showScale` — `boolean` default `false`. Prints the scale's two ends under each track. - `className` — `string`. Merged onto the figure, last, so a call site can size or space it. - `hideDataTable` — `boolean` default `false`. Drops the hidden table view. Only correct when the page prints the data itself. - `empty` — `ChartEmptyProps`. What the chart shows when it has nothing to draw. ## Example — default ```tsx import { BulletChart } from '@misoto22/design/charts' ``` ## Example — per measure scales ```tsx import { ToggleGroup, ToggleGroupItem } from '@misoto22/design' import { BulletChart, formatNumber } from '@misoto22/design/charts'
next && setShowScale(next === 'shown')} aria-label="Scale labels" > no scale scale
```