Progress

The markup is a track and a span for each part

The span's inline width is its part of the track. A bar that shows a single value gets role="progressbar" and aria-valuenow on the track.

Height with data-size: sm 4px, default 6px, lg 12px, xl 32px

data-variant on a span sets its colour

Without it, the span uses the main text colour (accent is only for links and primary buttons). The others are ok, warning, info and danger.

A label and the value above the track

Put a <header> right before the track, with the label on the left and the value on the right. Link the label with aria-labelledby and give a readable value with aria-valuetext.

Product image storage 7.8 GB of 10 GB

Several spans divide the track

Parts without a colour go from dark to light. A bar split into parts uses role="img" and an aria-label that names every part. Use at most 5 parts.

data-variant="empty" leaves a gap

An empty span draws nothing, so the next part starts mid-track. Good for ranges or values compared with a midpoint.

The extra large track with a list under it shows how a total divides

A <ul> right after the track gets markers that match the part in the same position. The number goes in the last span of each row.

Cancellations by reason

678 cancellations in the last 30 days

  • Other60%
  • Recurring payment declined23%
  • Not satisfied with quality9%
  • Too expensive5%
  • Changed my mind3%

The page moves the bar by setting width and aria-valuenow together

Tsunami has no JS for progress. The page sets both values itself. This example uses a short inline script.

Native <progress>

For a simple single value, you can use <progress class="progress">. It has progressbar semantics built in. Put data-size and data-variant on the element.

40%

Attributes

Attribute / element Values Description
.progress Full-width track, 6px tall, subtle fill, 4px corners. Use on a <div> (with spans) or a <progress>.
data-size sm, lg, xl (omit for 6px) On the track: sm 4px, lg 12px, xl 32px.
> span One part of the track. Set style="width: N%". Adjacent parts have a 2px divider. Parts without a colour fade from --fg (positions 1-5).
> span[data-variant] ok, warning, info, danger, empty (omit for --fg) The part's colour. empty draws nothing and acts as a spacer so the next part starts mid-track.
progress[data-variant] ok, warning, info, danger Colour of a native <progress>.
role progressbar, img On the track: progressbar for a single value, img for a bar split into parts (with an aria-label that names every part).
aria-valuenow Number The current value on a progressbar track. Set it together with the span's width.
aria-valuemin 0 Minimum value.
aria-valuemax 100 Maximum value.
aria-valuetext Text Optional. The value read aloud, e.g. "7.8 GB of 10 GB".
aria-label Text Name of the bar.
aria-labelledby id Use instead of aria-label when the label is shown in the header.
header + .progress <header> before the track. The first child is the label, the last child is the value, muted and right-aligned, 12px text.
.progress + ul > li List after the track. Each row gets the marker colour of the part in the same position. The last span in a row is the value, right-aligned and bold.

API

Progress has no script, functions or events. The page sets the span's style.width and aria-valuenow (and aria-valuetext if used) together. Width changes animate smoothly over 0.3s (no animation with reduced motion).