Rollout Ruler
Set a feature’s rollout stage and show when a kill switch rolls it back.
import { RolloutRuler, RolloutStage } 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 rollout ruler to show and set how far a feature has rolled out: internal, beta, 10%, 50%, GA. The track is cut into its stages, each an equal stretch, so the early cohorts get as much room as the late ones; the axis under it says what each gate is worth. For a free percentage, use a Slider.
import { RolloutRuler } from '@youj/react'
const [share, setShare] = useState(10)
<RolloutRuler label="Rolled out to" value={share} onValueChange={setShare} />value is the share of users, 0–100, and while it's interactive it's always a stage's value (or 0). The default stages are Internal 1%, Beta 5%, 10%, 50% and GA 100%; pass stages for your own, in any order:
<RolloutRuler
stages={[
{ value: 0.5, label: 'Canary' },
{ value: 2, label: 'Staff' },
{ value: 25, label: '25%' },
{ value: 100, label: 'All' },
]}
/>Ticks already rolled out light in tone (the accent), the stretch to the next gate is a runway at a third of it, and the gate the value sits on names itself in the tone. A kill switch is a change from outside: set value to 0 (with tone="danger") and the ruler sweeps back tick by tick.
Description
A ruler at 10% with a kill switch that rolls it back to 0, and a button that restores it.
Four flags as small read-only rulers, one per row.
readOnly makes it a meter with no playhead, and size="sm" is the bare track for a list row, one per flag.
Code
rollout-ruler-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsvalue, defaultValue, onValueChange… (12)
Props
| Prop | Type | |
|---|---|---|
value | numberThe share rolled out, 0–100. Interactive, it's always a stage's value (or 0). | – |
defaultValue | numberdefault 0 | 0 |
onValueChange | (value: number) => void | – |
onValueCommitted | (value: number) => voidCalled once a drag or key press ends, with the final value. | – |
stages | readonly RolloutStage[]The gates, in any order. Default: Internal 1%, Beta 5%, 10%, 50% and GA 100%. | – |
readOnly | booleanA meter to read, without a playhead to move. default false | false |
disabled | booleandefault false | false |
size | 'default' | 'sm'
default 'default' | 'default' |
tone | RolloutTone'accent''success''warning''danger''neutral'The lit ticks. default 'accent' | 'accent' |
label | stringThe visible name over the track, and its accessible name. Default: the labels' "Rollout". | – |
ticks | numberMinor intervals per stage. Default 10, or 5 at | – |
locale | stringDefault: the YoujProvider locale. | – |
Other props pass through: extends ComponentProps<'div'>. | ||
MotionA step you take, A change from outside, reveal · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| A step you takedrag, a press on the ruler or a key: the playhead snaps to the gate | spring.snappy0.2s, bounce 0 | 0.2s, bounce 0 | |
| A change from outsidea kill switch or a schedule: the ticks light or go dark one after another at a constant rate, the playhead riding the front | duration.deliberateease.linear560ms · cubic-bezier(0, 0, 1, 1) | 560mscubic-bezier(0, 0, 1, 1) | |
| Revealit sweeps up from zero as it scrolls into view | duration.deliberateease.linear560ms · cubic-bezier(0, 0, 1, 1) | 560mscubic-bezier(0, 0, 1, 1) |
Reduced motion
Drawn at its value; changes jump.
Reduced motion
The ruler is drawn at its value, and changes jump without the sweep.
AccessibilityKeyboard
Accessibility
- Interactive, it's a slider over the stages, named by
label(or the labels' "Rollout"). Its value is spoken with the stage's name: "Beta at 5%", "50%", "Off". - The arrow keys and Page keys step one gate; Home and End go to off and the last stage. A press anywhere on the ruler moves to the nearest gate.
readOnlyandsize="sm"are meters with the same spoken value.- Its built-in text (the default stage names, "Off") comes from the labels, so
<YoujProvider labels>translates it.