Skip to content

Stepper

<caos-stepper>

the steps of a guided flow, which one you are on, and which are done

May be placed on a step of a guided flow.

Name Attribute Description Type Default Required
steps property only The steps, in order, as { key, label, description?, state? } objects or as plain strings. A string is shorthand for a step whose key and label are the same word. key is what current names and what a selection reports; description is one quieter line under the label. An empty list draws nothing rather than an empty rail. json empty list Optional
current current, also a property The key of the step being worked on. Every earlier step reads as completed and every later one as still to come, so moving a flow forward is one assignment rather than a rewritten list. A key that matches no step leaves every step reading as still to come, which is the honest drawing of “this flow has not started”. text none declared Optional
orientation orientation, markup only Which way the steps run. vertical is the rail the wizard blueprint pins beside the content; horizontal is the band across the top of a surface that has no rail. Anything unrecognised reads as vertical. text — recognises vertical, horizontal; anything else reads as vertical vertical Optional
interactive interactive, markup only Let somebody return to a step they have already finished. Only a completed or failed step becomes a control; the step in hand and the ones still ahead never do, because a rail that offers a step the flow cannot yet answer is offering something that does not work. Without this the rail is a report and nothing in it is clickable. boolean false Optional
label label, markup only What the sequence is called, used as the accessible name of the list. Unset leaves the list unnamed, which is what a rail with a visible heading beside it should do rather than saying the same thing twice. text none declared Optional
Name When it fires What it carries
caos-step-select A completed or failed step is chosen, and only while interactive is set. The rail does not move itself; the page decides what going back means. { key, index } — which step was chosen, and where it sits in the list.

Nothing goes inside this piece.

Design token What it controls
--caos-font The typeface of a step label and its supporting line.
--caos-font-mono The typeface of the step number inside the marker.
--caos-color-text The label of the step in hand and of a completed one.
--caos-color-text-muted A step still to come, and every supporting line.
--caos-color-border The marker outline of a step still to come, and the line joining the steps.
--caos-color-surface The fill inside a marker.
--caos-color-accent The marker of the step being worked on.
--caos-color-success The mark and outline of a completed step, and the line behind it.
--caos-color-danger The mark, outline and label of a failed step.
--caos-state-selected-bg The tint behind the step being worked on.
--caos-state-hover-bg The tint behind a reachable step under the pointer.
--caos-state-disabled-opacity The dimming of a step still ahead, while the rail is offering a way back to an earlier one.
--caos-focus-ring The ring on a reachable step reached by keyboard.
--caos-radius-sm The corner radius of a step row.
--caos-radius-pill The roundness of the marker.
--caos-space-2 The padding inside a step row, and the gap beside the marker.
--caos-space-3 The gap between the marker and the label, and the length of the joining line.
Name Description Arguments
stateOf() The state one step is drawn in — what it declared, or what its position implies. Exposed because it is the whole judgement this piece makes, and anything that re-derives it is reading its own copy of the rule rather than the one that draws. index: number

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(list) the whole sequence Always
::part(step) one step — a button where it can be returned to, and otherwise not a control Always
::part(marker) the numbered disc, or the success or danger mark that replaces the number Always
::part(label) the name of a step Always
::part(description) the quieter line under a label Only on a step that declares a description. A step without one carries nothing under this name.
::part(connector) the line joining one step to the next, drawn in the success colour once the step above it is complete Between steps only. The last step has nothing after it, so it carries no connector.

When there is a sequence somebody is partway through and the order matters. If the parts can be done in any order, they are not steps and a rail claiming otherwise is wrong about the thing it draws.

  • ProgressBar — The progress is a quantity rather than a set of named stages.
  • TabStrip — The parts are facets of one thing that can be visited in any order.
  • Breadcrumb — You are showing where a page sits in a hierarchy, not progress through a flow.
  • Tree — The sequence is really a nested structure somebody navigates.

An ordered list of list items, so the count and the order are announced rather than implied by drawing. The step in hand carries aria-current="step". Every marker is hidden from assistive technology: the number repeats the list position and the success or danger mark repeats what the label and aria-current already say, so announcing them again is noise. A step that can be returned to is a real button and reachable by keyboard; one that cannot is not dressed as a control, which is the difference between a rail that reports and one that lies about what it offers. Name the sequence with label unless a visible heading beside it already does.

Four steps with the third in hand: the two before it are complete, the one after is still to come. This is the shape the wizard blueprint pins beside the step content.

{
"id": "example",
"section": "The wizard rail",
"columns": 1,
"items": [
{
"id": "stepper_1",
"type": "component",
"key": "stepper",
"inputs": {
"label": "Set up your org",
"current": "people",
"steps": [
{
"key": "org",
"label": "Organisation",
"description": "Name it and pick a region."
},
{
"key": "objects",
"label": "Objects",
"description": "The records you keep."
},
{
"key": "people",
"label": "People",
"description": "Who gets in, and what they may see."
},
{
"key": "review",
"label": "Review",
"description": "Check it over before it goes live."
}
]
}
}
]
}
<caos-stepper id="stepper1" label="Set up your org" current="people"></caos-stepper>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const stepper1 = document.getElementById('stepper1');
stepper1.steps = [
{
"key": "org",
"label": "Organisation",
"description": "Name it and pick a region."
},
{
"key": "objects",
"label": "Objects",
"description": "The records you keep."
},
{
"key": "people",
"label": "People",
"description": "Who gets in, and what they may see."
},
{
"key": "review",
"label": "Review",
"description": "Check it over before it goes live."
}
];

The one state position cannot imply. The second step declares error, so it keeps that state while the flow has moved on past it — and with interactive set it is one of the two kinds of step somebody may go back to.

{
"id": "example",
"section": "A step that failed",
"columns": 1,
"items": [
{
"id": "stepper_1",
"type": "component",
"key": "stepper",
"inputs": {
"label": "Import your data",
"current": "map",
"interactive": true,
"steps": [
{
"key": "upload",
"label": "Upload"
},
{
"key": "validate",
"label": "Validate",
"description": "Nine rows have no account.",
"state": "error"
},
{
"key": "map",
"label": "Map columns"
},
{
"key": "import",
"label": "Import"
}
]
}
}
]
}
<caos-stepper id="stepper1" label="Import your data" current="map" interactive></caos-stepper>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const stepper1 = document.getElementById('stepper1');
stepper1.steps = [
{
"key": "upload",
"label": "Upload"
},
{
"key": "validate",
"label": "Validate",
"description": "Nine rows have no account.",
"state": "error"
},
{
"key": "map",
"label": "Map columns"
},
{
"key": "import",
"label": "Import"
}
];

The same sequence running horizontally, for a surface with no rail to pin it beside.

{
"id": "example",
"section": "Across the top",
"columns": 1,
"items": [
{
"id": "stepper_1",
"type": "component",
"key": "stepper",
"inputs": {
"orientation": "horizontal",
"current": "pay",
"steps": [
"Basket",
"Address",
"Pay",
"Done"
]
}
}
]
}
<caos-stepper id="stepper1" orientation="horizontal" current="pay"></caos-stepper>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const stepper1 = document.getElementById('stepper1');
stepper1.steps = [
"Basket",
"Address",
"Pay",
"Done"
];