Bullet
A compact measure-vs-target readout: a value bar over qualitative range bands with a target marker.
@garn/ui/bulletDefault
A value bar over three range bands with a target tick.
Kpis
A labelled stack of bullets — a compact KPI list.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add bullet- Registry
bullet- Source
- bullet.tsx
- Deps
- None
- Registry deps
utils
Import
import { Bullet } from "@garn/ui/bullet";Props
Generated from the component's TypeScript types.
color- Description
- Measure-bar colour (token ref).
- Type
string
max- Description
- Scale max (default: the largest of value / target / ranges).
- Type
number
ranges- Description
- Qualitative range thresholds → muted background bands (e.g. [50, 75, 100]).
- Type
number[]
target- Description
- A comparison marker (target / prior period).
- Type
number
valueRequired- Description
- The measure (the actual value).
- Type
number
valueLabel- Description
- Accessible reading for the value (e.g. "$78k").
- Type
string
Plus 278 inherited native <div> attributes.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="bullet"][data-slot="bullet-ranges"][data-slot="bullet-measure"][data-slot="bullet-target"]Overview
Bullet is Stephen Few's answer to the gauge: a single value read against a target and a few qualitative bands (poor/ok/good), in a fraction of a gauge's space. It's ideal in dense contexts — a table cell, a KPI row — where you need measure-vs-target at a glance. It's a meter for assistive tech, so the value and target are announced, not just drawn.
Guidelines
Prefer it to a gauge when space is tight. A row of bullets compares many KPIs far better than a wall of dials. Reach for Gauge only when a single, large, standalone dial is the point.
Give the bands meaning. The qualitative ranges should map to real thresholds (e.g. target zones); keep them muted so the measure bar and target tick stand out. An explicit max fixes the scale (the value clamps to it); omit it to auto-fit.
Announce value + target. Pass an aria-label; the component folds the value and target into aria-valuetext so screen-reader users get the comparison, not just a number.
Best practices
- Pass an
aria-label; set atargetand meaningfulranges. - Use an explicit
maxwhen the scale is fixed (e.g. 0–100).
- Don't stuff many bands in — 2–3 qualitative zones read best.
- Don't use it where a full trend or breakdown is needed.
Accessibility
- Role
meter
- • role=meter with aria-valuenow (clamped) / aria-valuemin / aria-valuemax; pass an `aria-label`.
- • aria-valuetext folds in the value label and the target (e.g. "78%, target 90").
- • The bands, bar, and target tick are decorative.
- Status
- Stable
- Version
v0.3.0- Introduced
v0.2.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.