Lollipop Chart
Compare many items on one value scale: a dot on a stem from a baseline each, sorted into a curve, with one item picked and named.
import { LollipopChart, LollipopDatum } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a lollipop chart to compare many items on one measure where the sign matters, like error budget left by SLO, score against par by team, or stock against target by shop. A table beside it can follow and lead the pick. For a few items' parts of a whole use a Share Bar; for values over time, a Chart. The Lollipop ranking card is built on it.
import { LollipopChart } from '@youj/react'
<LollipopChart
label="Budget left by SLO"
data={slos.map((s) => ({ id: s.id, label: s.name, value: s.budget, tone: s.budget < 0 ? 'danger' : 'success' }))}
sort="ascending"
domain={[-1, 1]}
value={picked}
onValueChange={setPicked}
formatValue={(v) => percent.format(v)}
/>Each item is a dot at its value on a stem from baseline (0 by default), in its tone. sort orders them lowest or highest first; without it they keep the data's order. The scale runs over domain (by default the data's range with the baseline, rounded out to even ticks). formatValue writes values in the tooltip, the pill and the spoken text, and formatTick the axis. Give it a height with a class (h-64 by default). No items shows the empty state.
Description
A made-up league's goal difference against par, sorted lowest first, each dot in its status tone. Sorted, the stems read as one curve from the worst to the best, below the baseline on one side and above it on the other.
value and onValueChange pick one item: its column gets a band, its dot a ring, and a pill over the plot names it with its value. A fixed domain and ticks keep separate charts on the same scale.
Code
lollipop-chart-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsdata, sort, value, onValueChange, domain, baseline, ticks…
Props
| Prop | Type | |
|---|---|---|
dataRequired | readonly LollipopDatum[] | – |
sort | 'ascending' | 'descending'Order the items by value, lowest first or highest first. Default: the data's order. | – |
value | string | nullThe picked item's id (controlled); | – |
defaultValue | string | nullThe item picked at first (uncontrolled). default null | null |
onValueChange | (id: string | null) => void | – |
domain | readonly [number, number]The value scale. Default: the data's range with the baseline, rounded out to the ticks. | – |
baseline | numberWhere the stems start. default 0 | 0 |
ticks | readonly number[]Values on the axis. Default: about five even steps across the domain. | – |
formatValue | (value: number) => stringWrites a value in the tooltip, the pill and the spoken text. Default: the locale's number format. | – |
formatTick | (value: number) => stringWrites an axis tick. default `formatValue` | `formatValue` |
locale | stringDefault: the YoujProvider locale. | – |
label | stringAccessible name. Default: the labels' "Lollipop chart". | – |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: lollipop-chart, lollipop-chart-flag-row, lollipop-chart-flag, lollipop-chart-axis, lollipop-chart-plot, lollipop-chart-grid, lollipop-chart-baseline, lollipop-chart-band, lollipop-chart-item, lollipop-chart-stem, lollipop-chart-dot and lollipop-chart-summary. The picked item has data-state="selected"; an item's tone is --lollipop-ink.
MotionGrow, pick · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Growthe stems grow from the baseline and the dots ride them out when a third of the chart scrolls into view | spring.smooth0.36s, bounce 0 | 0.36s, bounce 0 | |
| Pickthe band and the pill glide to the picked item; its dot grows a ring | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Drawn in place; a new pick lands at once.
Reduced motion
The stems and dots are drawn at their values, and the band and pill jump to a new pick.
AccessibilityKeyboard, focus, screen readers
Accessibility
- A named
listbox(yourlabel, or the labels' "Lollipop chart") described by the count and the range ("18 points, from -82.3% to +94.1%."). - Every item is an
optionnamed with its label and value,aria-selectedwhen picked. - One tab stop. The arrow keys walk the items (mirrored in RTL),
HomeandEndgo to the ends, andEnterorSpacepicks; focus shows the same tooltip as hovering. - The axis, gridlines and stems are decorative. Tones never carry the meaning alone: the values are signed and spoken.
- Its built-in text comes from the labels, so
<YoujProvider labels>translates it.