Skip to content

Steps ​

WxSteps is a sequence with a place in it: what is done, where you are, and what is left.

  1. 2DeliveryWhere it goes
  2. 3PaymentHow it is paid
  3. 4Done
Down the page
  1. UploadA CSV of up to 5 MB
  2. 2Map columnsMatch them to fields
  3. 3ReviewCheck a sample of rows

Usage ​

vue
<script setup lang="ts">
const current = ref(0)
</script>

<template>
  <wx-steps :current="current" aria-label="Checkout">
    <wx-step title="Details" description="Who it is for" />
    <wx-step title="Delivery" description="Where it goes" />
    <wx-step title="Payment" />
  </wx-steps>
</template>

It shows the place; it does not hold it. current is yours, and so is whatever is rendered underneath — a wizard that owned its own position would fight the router the first time somebody refreshed on step three.

Going back, never forward ​

clickable lets a finished step be pressed to return to it, and @change reports which. Steps ahead are never offered: they are the ones that have not been filled in, and offering them is a promise the form cannot keep.

Only finished steps render as buttons at all, so there is nothing for a keyboard to land on that would do nothing.

Something went wrong ​

error marks the current step as failed without moving off it — a payment refused, a validation the server rejected. The step keeps its place; only its colour and its glyph change.

Too narrow to be a row ​

Across the page a step is a marker, a title and a line of explanation side by side; on a phone there is room for about one of those. Rather than wrap every title to a letter a line, a horizontal sequence turns down the page on its own once a step would be narrower than minStepWidth — 132 pixels by default. :min-step-width="0" keeps it across the page whatever the room.

How many steps there are is half the question, so this is a measurement of the sequence's own box rather than a media query: four steps need twice the room two do, and it is the panel a wizard sits in that decides, not the window.

Numbering ​

The steps report themselves in the order they are written, while the component sets up rather than after it mounts. That matters: a sequence that numbered itself one frame later would flicker on every page carrying a wizard.

The rule between them is a pseudo-element chosen by :last-child, for the same reason — a step that had to be told how many siblings it has cannot know on its first render.

Steps ​

PropTypeDefaultDescription
currentnumber0Which step, counting from zero
direction'horizontal' | 'vertical''horizontal'Across, or down the page
size'sm' | 'md''md'Marker and title size
errorbooleanfalseThe current step went wrong
clickablebooleanfalseFinished steps can be returned to
minStepWidthnumber132Narrower than this and it folds down the page; 0 never
ariaLabelstring—Accessible name of the sequence

Events: change (index) — a finished step was chosen.

Step ​

PropTypeDefaultDescription
titlestring—What this step is
descriptionstring—What it involves
iconIconName—Instead of the number

Slots: title; default — the description; marker — with { index, state }.

Accessibility ​

The sequence is an ordered list, which is what it is, and the current step carries aria-current="step". The state is never colour alone: a finished step shows a tick, a failed one a cross, and the ones ahead their number.

Released under the MIT License.