flyingsalmon

Stepper

A display-only bar of equal segments, filled through the current one, for a position in a sequence whose count is known. It reads as ticks, not as a fraction.

Stepper, progress, timeline, tabs

Progress is a fraction of one operation with a known end: a machine is working and the bar says how far it got. Stepper is a position in a sequence a person is walking: turn 2 of 4, with nothing partial about turn 2. Timeline is a layout of markers joined by connectors, each carrying its own content and no item state. Tabs navigate between peer panels. Stepper has no markers, no connectors, no fraction, and no navigation.

It is domain-blind: it takes count and current and paints segments through the current one. The app maps its own notion of a step onto those two numbers and writes the position text.

Forward and back

current is 1-based and clamps to [1, count], so a step past the end or below the start never draws past the bar. Advancing fills the reached segment from its left edge with a spring that overshoots inside the segment's own box; going back un-fills it without a wobble. The current segment paints the same as a completed one — a display-only bar has no reason to distinguish where you are from what you have done, and data-state="current" is the hook for an app that wants a third look.

Light
Turn 1 of 4
Dark
Turn 1 of 4

A growing count

count may change while the bar is mounted. New segments render as upcoming with no enter animation, because a segment appearing is a change to the plan rather than movement through it.

Light
Turn 2 of 3
Dark
Turn 2 of 3

The app owns the text

The stepper has no text slots and no segment labels. “Turn 2 of 4” is the bar plus the app's own line, because only the app knows what a step is called. Compose the two.

Light
Planning your tripTurn 2 of 4

Next: who is coming with you

Dark
Planning your tripTurn 2 of 4

Next: who is coming with you

States

The bar is not interactive: no hover, no focus, no press, no disabled, and no tab stop. Each segment carries its own data-state, which is complete, current, or upcoming. There are two paints: segments through current on --progress-fill, the rest on --progress-track. Both tokens come from the theme, which is why the stepper does not depend on the progress item.

The fill clears the track at 3.72:1 in light mode and 4.3:1 in dark, so the edge between a filled segment and an empty one is readable without color vision. The track sits at 1.26:1 against the page, enough to show how many segments are left.

Accessibility

The bar is a list named by label, which defaults to “Progress”. Each segment is a listitem named “2 of 4”, and the current one carries aria-current="step", so a screen reader reads “2 of 4, current step”. Nothing else sits on the root, and nothing in the bar takes focus.

A note on the name

Elsewhere “stepper” names the minus and plus pair beside a numeric input. In this registry that pair belongs to number-field and is called spin buttons, the name its ARIA role already uses. stepper is this bar, because it is the word a consumer searches for when they want one.