v3.0.0
ProgressStepsList

A vertical list of the steps of a multi-step flow, each with its status and description.

-- -- -- 3.0.2

Step 2 of 3, Pick up, in progress

Overview

ProgressStepsList shows every step of an ordered flow with its details — a courier delivery: go to the sender, pick up, go to the recipient, drop off. Each step is a row: a small squircle whose look follows the step's status, on a line that runs down to the next step, and beside it the step's description — DefaultItem, a Cell with a title and a subtitle, or a team's own layout. It is the full form of the flow; ProgressStepsCompact is the compact row that opens it.

  • 1
    DefaultItem
  • 2
    Tappable DefaultItem
  • 3
    Skeleton

Step 2 of 3, Pick up, in progress

  1. Step 1 of 3, completed. Go to sender
    58 Zhandosov Street
  2. Step 2 of 3, in progress. Pick up
    58 Zhandosov Street
  3. Step 3 of 3, upcoming. Go to recipient
    56 Samal-2 Micro District

Step 2 of 3, Pick up, in progress

Loading

States

The list has three states — Standard, Skeleton and Disabled. Each step shows its status through the Squircle's own states; a tappable DefaultItem presses and takes focus as a Cell.

Step Status

Step 3 of 4, Go to recipient, in progress

  1. Step 1 of 4, completed. Go to sender
    58 Zhandosov Street
  2. Step 2 of 4, cancelled. Pick up
    58 Zhandosov Street
  3. Step 3 of 4, in progress. Go to recipient
    56 Samal-2 Micro District
  4. Step 4 of 4, upcoming. Drop off
    56 Samal-2 Micro District
  • 1
    Completed Squircle Disabled — --surface-on-white with --text-and-icon-disabled.
  • 2
    Cancelled Squircle Standard with the content re-pointed — --squircle-content = --text-and-icon-error.
  • 3
    Current Squircle Inverse with the content re-pointed — --background-inverse-primary with --double-color-outline-inverse. One per list at most.
  • 4
    Upcoming Squircle Standard — --surface-on-white with --text-and-icon-primary.
  • Colour Only The status is drawn by colour alone; the step's description keeps its own colours whatever the status. Assistive tech hears the status in words (Accessibility).

Skeleton

Loading

Loading

  • 1
    Skeleton Step A Squircle S in its own Skeleton state — .squircle--skeleton: --skeleton-on-white, content hidden, the shimmer --pattern-shimmer.
  • 2
    Divider Unchanged — --border-default; none under the last row.
  • 3
    Text Bars Two DS .skeleton bars: full width × var(--sp-100-s16), then var(--sp-100-s120) × var(--sp-100-s12); radius var(--sp-100-s8), var(--sp-100-s4) apart and above and below.
  • 4
    RTL Mirrored — the squircles on the right, the bars aligned to the right and the shimmer running right to left.
  • Static Shape Four rows, whatever the flow's length — it is not known while loading. A Skeleton in the form of the team's own steps is built on the custom base (Usage).
  • Loading Root: .progress-steps-list--skeleton, data-ds-state="skeleton"; the placeholder list is aria-hidden; the phrase reads "Loading" — no aria-busy: the phrase is the live region, and a busy one holds its own announcement back.When the steps land, the host swaps the rows in the same root and writes the position into the same phrase — announced once.

Disabled

Step 2 of 3, Pick up, in progress

Step 2 of 3, Pick up, in progress

  • 1
    Standard The same list in Standard, for comparison.
  • 2
    Steps Every StepItem takes the Squircle's own Disabled state — .squircle--disabled: --surface-on-white with --text-and-icon-disabled — in place of its status.The statuses are not drawn; each step's prefix still speaks them.
  • 3
    Divider Unchanged — --border-default.
  • 4
    EndSlot Content Takes its own Disabled state: DefaultItem is the Cell's .is-disabled — title, subtitle and chevron in --text-and-icon-disabled.A tappable DefaultItem carries aria-disabled="true" — reachable, the press and the tap refused. A team's own content handles its Disabled itself.
  • Markup Root: .progress-steps-list--disabled and data-ds-state="disabled". Not staged in Figma — an owner ruling.

Tappable DefaultItem

Step 2 of 3, Pick up, in progress

  • 1
    Standard The cell at rest, the chevron at its end — the sign the step opens.
  • Pressed The Cell's own press — --shadow-pressed, --component-push-highlight.
  • Focused Web, keyboard focus: the Cell's inset var(--sp-s2) outline in --text-and-icon-primary, :focus-visible only.
  • Disabled With the list's Disabled state only — see above.

Anatomy

A vertical stack of rows, one per step: a squircle on a line that runs down to the next step, and the step's description beside it.

Step 2 of 3, Pick up, in progress

  • 1
    Container A full-width column of steps, no gap — the Divider joins them; transparent, it sits on the host's surface.Required.
  • 2
    ListStepItem One row per step: StartSlot and EndSlot. At least 64 high, as tall as its content.Required, two and up.
  • 3
    StepItem A Squircle S in StartSlot; its State follows the step status. The content is the step's number (Text) or an icon (Icon). The same building block as ProgressStepsCompact.Required.
  • 4
    Divider A vertical line under the squircle — var(--sp-s2) wide, radius var(--sp-100-s8), --border-default — running down to the next step.On every step but the last.
  • 5
    EndSlot The step's description; fill width, at least var(--sp-100-s24).Required. Holds DefaultItem or a team's own DS layout.
  • 6
    DefaultItem A Cell, its padding and floor removed: a title (Main Body) and an optional subtitle (Compact Body, --text-and-icon-secondary).Not tappable by default; tappable, it shows the cell-chevron and the whole cell is the target.

Layout

Paddings and gaps are fixed (SP/100%), the squircle stops at 130 %, the text scales in full.

Spacing

Step 2 of 3, Pick up, in progress

  • 1
    Row Padding var(--sp-100-s20) on the start and end sides, none on top and bottom; the row at least var(--sp-100-s64).
  • 2
    StepItem Box var(--sp-130-s40), radius var(--sp-130-s16) — cap130.
  • 3
    Divider var(--sp-100-s4) below the squircle; it fills the row and stops var(--sp-100-s4) above the next squircle (StartSlot's bottom padding).
  • 4
    DefaultItem At least var(--sp-130-s40) — the squircle's height, so the text centres on it; var(--sp-100-s4) under EndSlot. The chevron sits at the end, var(--sp-s8) from the text (the Cell's gap).
  • Slot Gap var(--sp-100-s8) from StartSlot to EndSlot.
  • Scaling At 130 / 150 % the squircle stops at 52 and the paddings stay put; the title and subtitle grow, and the rows grow with them.
  • Width The list takes its host's full width — 360 in the Figma set. It does not scroll itself: a long flow is scrolled by its screen.

Step Content And RTL

Step 2 of 4, Pick up, in progress

Step 2 of 4, Pick up, in progress

  • 1
    Icon A courier flow: person-courier, info-outline (current), courier-walk, courier — a 24 glyph, var(--sp-s24), in the squircle's content colour.
  • 2
    RTL dir="rtl": StartSlot on the right, the text aligned right; the chevron and courier-walk (.progress-steps-list__icon--rtl) mirror, the numbers and other icons do not.
  • Text Or Icon A step holds its number (.squircle--text) or an icon (the bare .squircle--s). One content type per list.

Animation

Step 1 of 4, Go to sender, in progress

  • 1
    Live Demo The buttons move the current step; the steps swap their statuses in place. Press or Tab to a step to see the Cell's press and focus.
  • DefaultItem Press The Cell's own --component-push-highlight — the --shadow-pressed overlay. A not-tappable DefaultItem does not press.
  • Status Change A swap: the step takes its new Squircle State in one frame — the Squircle declares no transition.
  • Skeleton The Squircle Skeleton and the bars run the DS sweep, --pattern-shimmer. Skeleton → Standard is a swap in one frame.
  • Divider Static — no motion.
  • Disabled No press and no tap; Standard ↔ Disabled swaps the squircle and Cell states, no transition.
  • Reduced Motion --component-push-highlight and --pattern-shimmer resolve to zero at the token; no override of its own.

Usage

Use ProgressStepsList for the full breakdown of an ordered flow, each step described — a courier route, a multi-stop ride, a document check — and as the screen ProgressStepsCompact's MoreButton opens. Where only the position matters and space is tight, use ProgressStepsCompact. Not for a continuous value (a Progress Bar), not as a stepper that moves the flow, not for a list with no order (Cell rows).

  • 1
    DefaultItem Title and subtitle, tapping on — each step opens its details.
  • 2
    Team Content The team's own EndSlot layout — a Heading 3 name with an order Tag and the address; its targets and spacing are the team's. Each step's prefix is still read first.

Delivery route

Step 2 of 4, Pick up, in progress

Delivery route

Step 2 of 3, Pick up, in progress

  1. Step 1 of 3, completed.
    Go to senderOrder 1

    58 Zhandosov Street, Residential Complex

    Courier: Dilnaz Ahmetov

  2. Step 2 of 3, in progress.
    Pick upOrder 1

    58 Zhandosov Street, Residential Complex

    Courier: Dilnaz Ahmetov

  3. Step 3 of 3, upcoming.
    Drop offOrder 1

    56 Samal-2 Micro District, Building 4

    Courier: Dilnaz Ahmetov

Custom Base

Step 2 of 3, Pick up, in progress

  1. Step 1 of 3, completed. Go to sender
    58 Zhandosov Street
  2. Step 2 of 3, in progress. Pick up
    58 Zhandosov Street
  3. Step 3 of 3, upcoming. Go to recipient
    56 Samal-2 Micro District

Step 2 of 3, Pick up, in progress

  1. Step 1 of 3, completed. Go to sender
    58 Zhandosov Street
  2. Step 2 of 3, in progress. Pick up
    58 Zhandosov Street
  3. Step 3 of 3, upcoming. Go to recipient
    56 Samal-2 Micro District
  • 1
    Re-Pointed Colours The Completed content --text-and-icon-success, the Divider --border-success.
  • 2
    IconContainer Steps The StepItem swapped for an IconContainer — Completed --text-and-icon-success, Current --text-and-icon-primary, Upcoming --text-and-icon-secondary; the row padding var(--sp-100-s16).
  • The Hooks Status colours — --progress-steps-list-{status}-fill / --progress-steps-list-{status}-content, status = completed · current · upcoming · cancelled; unset, the Squircle states' own values.Divider — --progress-steps-list-divider (--border-default) and --progress-steps-list-divider-width (var(--sp-s2)).Paddings — --progress-steps-list-padding-inline (var(--sp-100-s20)) and --progress-steps-list-gap (var(--sp-100-s8)).StepItem — another DS component keeps .progress-steps-list__step; an IconContainer adds .progress-steps-list__step--icon-container and takes its colour through its own color.
  • Contract An instance on the custom base carries data-ds-preset="custom". A re-pointed colour is the team's contrast check; the spoken prefixes are unchanged.

Accessibility

An ordered list, one element per step, read as its position and status first. The squircles, numbers, icons and Dividers are not announced. Full spec: progress-steps-list-a11y.md.

Step 2 of 3, Pick up, in progress

  • 1
    Step Prefix Each step starts with "Step N of M, status" — completed, in progress, upcoming, cancelled — then its content: "Step 2 of 8, in progress. Pick up, 58 Zhandosov Street". M counts the whole flow.TalkBack: the step merges its descendants (mergeDescendants) with collectionItemInfo; the StartSlot is cleared. VoiceOver: children: .combine, the StartSlot hidden.Web: an <ol role="list"> of <li> — the explicit role because WebKit drops a list-style: none list's semantics; the prefix a .visually-hidden span inside the title; the StartSlot and chevron aria-hidden. No aria-current — the prefix already says "in progress".
  • 2
    Tappable DefaultItem A button whose name starts with the prefix — "Step 2 of 3, in progress, Pick up, 58 Zhandosov Street". TalkBack Role.Button; VoiceOver .button, hint "Opens the step's details."The trap: the cell is 40 high; growing it to 48 in layout moves the Divider. The touch region expands instead — on the web a transparent ::before var(--sp-100-s4) beyond its top and bottom.
  • List Phrase A .visually-hidden paragraph with role="status" names the current step — "Step 2 of 8, Pick up, in progress". It stays in the DOM and only its text changes, so a change is announced once and the first render is not.TalkBack: a polite liveRegion on a summary node before the list — a swipe stop by design. VoiceOver: a queued announcement (.accessibilitySpeechQueueAnnouncement) — a plain one interrupts.Cancelled steps are not appended — each says "cancelled" in its own prefix. In browse mode the phrase is read once before the list, and the current step again in its prefix — a deliberate repeat.
  • Team Content Keeps its components' own semantics — a Button stays a button. The step is a container, not one merged element (TalkBack no mergeDescendants, VoiceOver children: .contain), so every control inside stays its own target; the prefix is the step's first element, so position and status are read first.
  • Keyboard And Focus Only tappable elements take focus, top to bottom in LTR and RTL. Enter and Space activate a tappable DefaultItem; its ring is the Cell's inset var(--sp-s2) outline in --text-and-icon-primary.
  • Skeleton The phrase reads "Loading"; the placeholders are hidden and nothing takes focus. No aria-busy — it would hold the live phrase back.
  • Disabled Every step keeps its prefix — the squircles no longer show the status, the prefix does.A tappable DefaultItem stays reachable and refuses activation: TalkBack "…, Button, Disabled"; VoiceOver "…, Dimmed, Button", no hint.The trap: aria-disabled="true" keeps the native button in the tab order but does not stop its Enter / Space click — the handler returns early while it is set.
  • Contrast Upcoming ≈ 15.7:1 Day; Current ≈ 12.9:1 Day.Cancelled --text-and-icon-error ≈ 3.5:1 and Completed --text-and-icon-disabled ≈ 1.9:1 Day — under WCAG 1.4.3 for sighted users; and the status is colour alone (WCAG 1.4.1) — in forced colours only Current keeps a mark. The prefix carries the status for screen readers. The Figma colours stay — the gap is accepted (owner, 2026-11-12).Forced colours: the Current step draws a CanvasText outline, the Divider takes GrayText, placeholders keep a GrayText edge.