Progress and meters
The browser's own <progress> for work under way and <meter> for a measure within known limits - a quota, a score. The value is an attribute, the browser announces it, and a progress without a value says the work has no known end.
Examples
progress on a <progress> with value and max; the words of the value go beside the bar, text-nowrap so the bar gives way, and the label names it.
<div class="form-field">
<label class="form-label" for="progress-basic-upload">Uploading photos</label>
<div class="hstack gap-12">
<progress class="progress" id="progress-basic-upload" value="40" max="100">40 %</progress>
<span class="text-muted fs-12 text-nowrap">40 %</span>
</div>
</div>
<progress class="progress" aria-label="Rebuilding pages"></progress>Tones and sizes
progress-{tone} for the tones, progress-sm and progress-lg for the height; progress-striped lays stripes on the bar, progress-animated moves them while motion is allowed.
<progress class="progress progress-success" value="75" max="100" aria-label="Published, 75 percent"></progress>
<progress class="progress progress-warning progress-sm" value="50" max="100" aria-label="Translated, 50 percent"></progress>
<progress class="progress progress-danger progress-lg" value="20" max="100" aria-label="Failed, 20 percent"></progress>
<progress class="progress progress-lg progress-striped progress-animated" value="60" max="100" aria-label="Deploying, 60 percent"></progress>Meters
meter on a <meter>: low, high and optimum divide the range, and the browser colours the value by the part it falls in - green in the good part, amber next to it, red in the far one.
<div class="form-field">
<label class="form-label" for="progress-meter-storage">Storage used</label>
<div class="hstack gap-12">
<meter class="meter" id="progress-meter-storage" value="3.1" min="0" max="10" low="7" high="9" optimum="0">3.1 of 10 GB</meter>
<span class="text-muted fs-12 text-nowrap">3.1 of 10 GB</span>
</div>
</div>
<meter class="meter" value="8" min="0" max="10" low="7" high="9" optimum="0" aria-label="Photos, 8 of 10 GB">8 of 10 GB</meter>
<meter class="meter" value="9.6" min="0" max="10" low="7" high="9" optimum="0" aria-label="Backups, 9.6 of 10 GB">9.6 of 10 GB</meter>Hairlines
progress-xs, 3 px, and meter-xs, 2 px, sit under a row's words without fighting them: how far a job is between its runs, amber when it is late, and how often it succeeded, colored by the meter's own parts.
<div class="vstack gap-4">
<span>Nightly backup <span class="text-muted fs-12">next in 2 h</span></span>
<progress class="progress progress-xs" value="70" max="100" aria-label="Nightly backup, 70 percent of its cycle"></progress>
<meter class="meter meter-xs" value="0.98" min="0" max="1" low="0.8" high="0.95" optimum="1" aria-label="Nightly backup, 98 percent succeeded">98%</meter>
</div>
<div class="vstack gap-4">
<span>Mail queue <span class="text-muted fs-12">late by 6 min</span></span>
<progress class="progress progress-xs progress-warning" value="100" max="100" aria-label="Mail queue, late"></progress>
<meter class="meter meter-xs" value="0.71" min="0" max="1" low="0.8" high="0.95" optimum="1" aria-label="Mail queue, 71 percent succeeded">71%</meter>
</div>Along the window's top
REDZ.ui.progress(promise) shows a thin bar along the top of the window while a request runs, and answers the promise: it comes after 150 ms, so a quick answer shows nothing, then stays at least 400 ms, so it never flickers; however many requests run at once, there is one bar. It is progress-top, in the top layer, and readers do not hear it - what waits says so itself, a busy region or button. Under reduced motion the bar stands still.
<button class="btn" type="button" data-docs-run="progress"><i class="bi bi-cloud-arrow-down" aria-hidden="true"></i>Load for 2 seconds</button>const rows = await REDZ.ui.progress(fetch('/bookings?page=2').then((answer) => answer.json()));
A product sets how much it shows in its tokens: --redz-progress-top-size, --redz-progress-top-track and --redz-progress-top-glow, a box-shadow.
Keyboard and accessibility
- Name every bar: a
<label for>,aria-labeloraria-labelledby. The browser announces the value as a percentage ofmax; the words beside the bar are for the eye. - Colour is not the message: a meter in the red part also says so in words where it matters.
- A screen reader does not follow a bar as it fills: say the end of a long task in a notice, by
REDZ.ui.toast. - In forced colours the bar takes the system's highlight; right to left it fills from the right.
Tokens
From css/components/progress.css. It declares --redz-track on its root, never on rows or items.
It reads the theme's --redz-bg-hover, --redz-primary, --redz-secondary, --redz-success, --redz-danger, --redz-warning, --redz-info, --redz-progress-top-track, --redz-progress-top-size, --redz-progress-top-glow, --redz-motion, --redz-ease.
From Bootstrap 5.3
| Bootstrap 5.3 | REDZ.UI | Change | Note |
|---|---|---|---|
progress | progress | review | on a <progress value="40" max="100"> itself, not around a progress-bar with a width; a tone is progress-success and the like, not bg-* on the bar |
progress-bar | - | remove | the browser draws the bar from value |
progress-bar-animated | progress-animated | rename | it moves only while motion is allowed |
progress-bar-striped | progress-striped | rename | |
progress-stacked | - | review | not planned: one <progress> a value |