Progress

Progress shows how far something has come, as HTML’s <progress> names it. It is one square high and takes three shapes: a value against its range (money spent of a budget, seats taken, a goal saved towards), a numbered sequence of steps (signing up, a checkout), or a dot for each slide or page. One element, ds-progress, draws all three; which one, it reads from what it is given.

Preparing an edition

A measured quantity, a square count and a step sequence express different kinds of progress.

Reading position

A short progress bar and its plain-language label.

A bar, squares and over

The words say the value and when it is past the end: 12 of 10, over by 2.

Where someone is

The current step is aria-current="step"; done steps say so in hidden words. The vertical sequence has room under each step.

Where you are, and where you can go

Click a dot, or focus one and use the arrow keys, Home and End. Each pick fires select.

<ds-progress label="Spent" value="7400" max="10000" format="money" currency="DKK"></ds-progress>
<ds-progress label="Seats" value="7" max="10" squares="10"></ds-progress>
<ds-progress label="Spent" value="118" max="100"></ds-progress>

A bar half a square high across the middle of the row (as a chart’s ratio is drawn), or, with squares="10", the range in ten squares, each one square wide and drawn one pixel short, as an item on the grid is, as many filled as the value fills. A value past the end is over: it fills whole in the danger colour, and its words say by how much. It shows a measurement, takes no keys and no focus.

The element is role="meter" with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext. aria-valuenow stays inside the range, as ARIA requires, so the words carry what the number cannot: “7 of 10”, or “12 of 10, over by 2”, in the shared words of the current language, the figures written as format says. valuetext gives words of the page’s own, label names it, and over shows the over state whatever the value. A native <meter> or <progress> cannot say it is over and is drawn differently in each browser, so this is a role="meter" element instead.

AttributeTypeDefaultWhat it does
valuenumber0The value.
min, maxnumber0, 1The range.
squaresnumberNoneDraw the range in this many squares instead of a bar (at most a hundred).
overbooleanfalseShow the over state whatever the value.
valuetextstring“7 of 10”What the value says.
format, currency, minor, whole, digitsnumberHow the figures in the words are written, as for a Stat.
<ds-progress current="2" label="Getting started"
steps='["Apply", "Approval", "Connect payouts", "Start earning"]'></ds-progress>

steps makes it a sequence: each step a number in a mark one control high and its name, on one square, joined to the next by a line. steps is a list of names (translation keys unless literal is set), set as a property or as a JSON array in the attribute; current is the number of the current step, counted from 1. Past the last, every step is done; 0 means none has started.

StateMarkNameSaid
Done (before current)check on the grey fillThe text colour“Done”
CurrentThe number in the paper colour on the inkThe medium facearia-current="step"
Upcoming (after current)The number in a 1px line, mutedMuted
Failedwarning on the danger colourThe danger colour“Failed”

A step names its own state with { "label": "Approval", "state": "failed" }, where something went wrong and the sequence stops there. The steps are an ordered list, so assistive technology reads how many there are and where each stands; the hidden words are the shared words in the current language. A step with href ({ "label": "Details", "href": "/details" }) is a link around its mark and name, reached with Tab, for going back to a step already done; the others take no focus.

vertical puts one step on each square, with what belongs under a step in its step-N slot, indented one square to line up with the names: a line of text, a form, the buttons that finish the step.

<ds-progress vertical current="3" steps='["Apply", "Approval", "Connect payouts", "Start earning"]'>
<p slot="step-3">Connect a payout account to get paid.</p>
</ds-progress>
<ds-progress dots="5" active="1"></ds-progress>

dots makes it a dot for each slide or page: one square apart, the current one filled and half again as large, those before it filled in the muted colour, the next in the text colour, the rest rings, so the row reads as how far you have come and where you go next. Each dot is a button that takes you to its page. A Carousel draws its own; use them alone for pages that move some other way.

Pressing a dot fires select with { index, previous }; unless a listener cancels it, the dot becomes current. Cancel it when the page decides, and set active once it has moved. end draws the last dot as a ring in the text colour, an end marker, unless it is current: the way on to something past the slides.

The dots are a group named “Slides”, each a button named “Slide 2”, the current one marked aria-current and the only one in the tab order. The arrow keys move to the dot before or after and pick it (following the reading direction), Home and End go to the first and last, and focus follows.

AttributeTypeDefaultWhat it does
dotsnumberNoneHow many dots.
activenumber0The current dot, from 0.
endbooleanfalseDraw the last dot as an end marker.
dot-labelstringThe shared words’ “Slide {index}”Each dot’s name, {index} its number from 1.

Shared by every shape: label, the element’s name (the dots’ group is the shared word “Slides” by default), and literal, which shows the words as written, never looked up.

One square high. The bar is half a square high, a quarter of a square from the top, the filled part in the ink (--ds-progress-color) on the grey fill (--ds-progress-track); it grows with a transform, still for reduced motion. In squares, each square is one square wide and one pixel short; over, everything is --ds-danger-color. Each step’s mark is one control (16px) in its own square, the name follows with 4px at its end, and the step rounds its width up to whole squares, the line to the next step filling at least one square of it; vertical steps stand one to a square, their bodies one square in. Each dot is a button one square wide and high; the dot itself is 4px, scaled with the surface, the current one half again as large, and only its size moves, not at all under reduced motion. The dot colours are --ds-progress-dot-past, -current, -next, -future and -end.

import { Progress } from "@0001-labs/design-system-1/DS1/react/progress";
<Progress label="Spent" value={spent} max={budget} format="money" currency="JPY" />
<Progress steps={[t("Apply"), t("Approval"), t("Connect payouts")]} current={2} vertical bodies={[null, null, <StripeActions />]} />
<Progress dots={pages.length} active={page} onSelect={setPage} />

A value puts the role and the values in the markup from the first render, on the server too. Steps arrive as a property, with each of bodies under its step; the words are written as given. Register ds-progress in the browser before hydration.

A value against its range is one value on one line, in a row, a tile or a table cell. Several values against each other are Chart’s bars (ds-bars), and two shares of a whole its ratio (ds-ratio).

Stat · Chart · Carousel