Skip to content

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/react

For 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.

Reference

Propsdata, sort, value, onValueChange, domain, baseline, ticks…

Props

LollipopChart props
PropType
dataRequiredreadonly LollipopDatum[]–
sort'ascending' | 'descending'

Order the items by value, lowest first or highest first. Default: the data's order.

–
valuestring | null

The picked item's id (controlled); null for none.

–
defaultValuestring | null

The item picked at first (uncontrolled).

default null

null
onValueChange(id: string | null) => void–
domainreadonly [number, number]

The value scale. Default: the data's range with the baseline, rounded out to the ticks.

–
baselinenumber

Where the stems start.

default 0

0
ticksreadonly number[]

Values on the axis. Default: about five even steps across the domain.

–
formatValue(value: number) => string

Writes a value in the tooltip, the pill and the spoken text. Default: the locale's number format.

–
formatTick(value: number) => string

Writes an axis tick.

default `formatValue`

`formatValue`
localestring

Default: the YoujProvider locale.

–
labelstring

Accessible 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

Motion tokens
MomentTokens
Growthe stems grow from the baseline and the dots ride them out when a third of the chart scrolls into view
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
Pickthe band and the pill glide to the picked item; its dot grows a ring
duration.baseease.standard

220ms · 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 (your label, or the labels' "Lollipop chart") described by the count and the range ("18 points, from -82.3% to +94.1%.").
  • Every item is an option named with its label and value, aria-selected when picked.
  • One tab stop. The arrow keys walk the items (mirrored in RTL), Home and End go to the ends, and Enter or Space picks; 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.