Score Ring
Show a score out of a range as a full ring of ticks lit up to it, with its letter grade in the middle.
import { ScoreGrade, ScoreRing } 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 score ring when one score carries a verdict: a security or health score with its letter grade, a compliance rating, a quality bar. The whole ring is the range and the lit ticks are the score, clockwise from the top, so how far round it reaches reads before the number; the tick at the score reaches past the rest. Pair it with the number itself (a Stat Card's StatValue) when the exact score matters. For a value on a scale with named bands and both ends shown, use a Gauge. The Score overview card is built on it.
import { ScoreRing, type ScoreGrade } from '@youj/react'
const grades: ScoreGrade[] = [
{ from: 0, label: 'F', tone: 'danger' },
{ from: 60, label: 'C', tone: 'warning' },
{ from: 75, label: 'B', tone: 'success' },
{ from: 90, label: 'A', tone: 'success' },
]
<ScoreRing value={77} grades={grades} label="Security score" />Each grade starts a band at from that runs up to the next one, in any order; the ring takes the band's tone and shows its label. Without grades it shows the score in tone (the accent by default). min and max set the range (0 to 100 by default) and the score is held inside it. ticks sets how many make the ring (40 by default), size is sm (64px), default (96px) or lg (128px), and children replaces what sits in the middle.
Description
A security score with letter grades from F to A, and buttons for 34, 62, 77 and 94 that move it. The ring takes the tone of the band the score is in, and the grade in the middle changes with it.
Without grades the middle shows the score and the ring takes tone; max sets any range (a credit score out of 850). busy circles a soft sweep inside the ring while a scan or a check runs.
Code
score-ring-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsvalue, max, grades, tone, ticks, size, busy…
Props
| Prop | Type | |
|---|---|---|
valueRequired | number | – |
min | numberdefault 0 | 0 |
max | numberdefault 100 | 100 |
grades | readonly ScoreGrade[]Bands in any order: the ring takes the tone of the one the score is in, and shows its label. | – |
tone | ScoreRingTone'accent''neutral''success''warning''danger''chart-1''chart-2''chart-3''chart-4''chart-5'The lit ticks' tone outside any grade. default 'accent' | 'accent' |
ticks | numberHow many ticks make the ring. default 40 | 40 |
size | 'sm' | 'default' | 'lg'The ring's size: default 'default' | 'default' |
busy | booleanA soft sweep circles inside the ring, for a scan or a check still running. default false | false |
format | Intl.NumberFormatOptionsIntl.NumberFormat options for the score. Default: whole numbers. | – |
locale | stringDefault: the YoujProvider locale. | – |
label | stringAccessible name. Default: the labels' "Score". | – |
children | ReactNodeThe middle. Default: the grade, else the score. | – |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: score-ring, score-ring-ticks, score-ring-tick, score-ring-sweep and score-ring-center. The root has data-size, data-tone (the band's tone, or tone) and data-yj-busy; a lit tick has data-yj-lit. The lit ticks' color is --score-ring-tone.
MotionReveal, relight, sweep · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Revealthe ticks light one after another up to the score when it scrolls into view | duration.deliberateease.standard560ms · cubic-bezier(0.2, 0, 0, 1) | 560mscubic-bezier(0.2, 0, 0, 1) | |
| New scorethe ticks between the old and the new score relight at once | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) | |
| Busya soft sweep turns inside the ring, once every six deliberate beats | duration.deliberateease.linear560ms · cubic-bezier(0, 0, 1, 1) | 560mscubic-bezier(0, 0, 1, 1) |
Reduced motion
Drawn at its score, with no sweep.
Reduced motion
The ring is drawn at its score, a new score lands at once, and busy draws no sweep (the ring still says it is busy).
AccessibilityMeter, value text, busy
Accessibility
- A
meter(yourlabel, or the labels' "Score") witharia-valuemin,aria-valuemaxandaria-valuenow, and a value text of the score of the maximum, then its grade: "77 of 100, grade B". busysetsaria-busy, so assistive tech knows the reading may change.- The ticks and the sweep are decorative; the value text says the score. A grade is a letter as well as a tone, never color alone.
- A dial turns clockwise in every script, so the ring keeps its direction under RTL.
- Its built-in text comes from the labels, so
<YoujProvider labels>translates it.