Component
Progress and meter
Segmented bars for how far a task has got, and where a measurement sits in its range.
Plain-text source, for agents and clipboard use: /components/source/progress.txt
When to use it
Progress shows a task that is under way and will finish, such as an import or a batch of confirmations, in brand teal. Meter shows a measurement within a known range, such as seats sold against what a departure needs to run, and takes a status colour from where the value sits. Both draw the value as a row of segments, and both are real progress and meter elements underneath, so the value is announced as a value.
Examples
Progress
A percentage, written by the script from the progress element when the value span has data-flux-percent.
<div class="flux-progress">
<div class="flux-progress__header">
<label class="flux-progress__label" for="progress-import">Importing rates</label>
<span class="flux-progress__value" aria-hidden="true" data-flux-percent>81%</span>
</div>
<progress class="flux-visually-hidden" id="progress-import" value="81" max="100">81%</progress>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>Progress with a count
When the units mean something, say them. Set the value text yourself; the script still draws the segments.
<div class="flux-progress">
<div class="flux-progress__header">
<label class="flux-progress__label" for="progress-confirmations">Sending confirmations</label>
<span class="flux-progress__value" aria-hidden="true">120 of 480</span>
</div>
<progress class="flux-visually-hidden" id="progress-confirmations" value="120" max="480">120 of 480</progress>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>Meter, higher is better
Seats sold on a departure that runs at 20 and is safe above 40. Above high is teal; between low and high is pending; below low is an error.
<div class="flux-meter">
<div class="flux-progress__header">
<label class="flux-progress__label" for="meter-seats-good">KB-2026-09-14 seats sold</label>
<span class="flux-progress__value" aria-hidden="true">44 of 49, guaranteed</span>
</div>
<meter class="flux-visually-hidden" id="meter-seats-good" value="44" min="0" max="49" low="20" high="40" optimum="49">44 of 49, guaranteed</meter>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>
<div class="flux-meter" data-tone="warning">
<div class="flux-progress__header">
<label class="flux-progress__label" for="meter-seats-pending">KB-2026-09-21 seats sold</label>
<span class="flux-progress__value" aria-hidden="true">30 of 49, 10 more to guarantee</span>
</div>
<meter class="flux-visually-hidden" id="meter-seats-pending" value="30" min="0" max="49" low="20" high="40" optimum="49">30 of 49, 10 more to guarantee</meter>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>
<div class="flux-meter" data-tone="error">
<div class="flux-progress__header">
<label class="flux-progress__label" for="meter-seats-low">KB-2026-09-28 seats sold</label>
<span class="flux-progress__value" aria-hidden="true">12 of 49, below the minimum of 20</span>
</div>
<meter class="flux-visually-hidden" id="meter-seats-low" value="12" min="0" max="49" low="20" high="40" optimum="49">12 of 49, below the minimum of 20</meter>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>Meter, lower is better
Set optimum below low to reverse the scale: an agent’s credit used turns pending at 60% and an error past 90%.
<div class="flux-meter" data-tone="warning">
<div class="flux-progress__header">
<label class="flux-progress__label" for="meter-credit">Credit used, Nordic Trails</label>
<span class="flux-progress__value" aria-hidden="true">ISK 4,050,000 of 5,000,000</span>
</div>
<meter class="flux-visually-hidden" id="meter-credit" value="4050000" min="0" max="5000000" low="3000000" high="4500000" optimum="0">ISK 4,050,000 of 5,000,000</meter>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>Small
flux-progress--sm halves the segment height, for a table cell or a dense list.
<div class="flux-progress flux-progress--sm">
<div class="flux-progress__header">
<label class="flux-progress__label" for="progress-small">Content import</label>
<span class="flux-progress__value" aria-hidden="true" data-flux-percent>35%</span>
</div>
<progress class="flux-visually-hidden" id="progress-small" value="35" max="100">35%</progress>
<div class="flux-segments" aria-hidden="true"><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item" data-filled></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span><span class="flux-segments__item"></span></div>
</div>Anatomy
| Part | Description |
|---|---|
| Header | The label, a label element bound to the progress or meter, and the value as text. |
| Value | The number in words or a percentage, in mono. It says what the colour says, so colour is never the only signal. |
| Element | A visually hidden progress or meter. It holds the value; change it there and the segments follow. |
| Segments | flux-segments, aria-hidden. Twenty by default, or the count in data-segments; a segment fills once its whole share is reached. |
API
| Name | Kind | Description |
|---|---|---|
flux-progress | class | A task under way. Holds a progress element and a flux-segments row. |
flux-meter | class | A measurement in a range. Holds a meter element with min, max, low, high and optimum. |
flux-progress--sm | class | The small segment height, on either wrapper. |
flux-segments | class | The segment row, aria-hidden. data-segments sets the count; twenty by default. |
data-flux-percent | attribute | On the value span: the script writes the percentage into it. |
data-tone | attribute | On flux-meter, set by the script from the meter’s region: warning when suboptimal, error when worse. Absent at optimum. |
States
| State | Treatment |
|---|---|
| Empty | No segment is filled until the value is above the minimum. |
| Partial | Any value above the minimum fills at least one segment, so started never reads as not started. |
| Complete | Every segment is filled only at the maximum. |
| Meter regions | Optimum in brand teal, suboptimal in the pending colour, even less good in the error colour. |
Keyboard
| Keys | Action |
|---|---|
— | Not interactive. |
Accessibility
- The progress or meter element is in the accessibility tree with its label, so assistive technology reads the value and the range.
- The value text says what the colour says. A meter in the error colour also says, in words, what is wrong.
- Progress changes are not announced as they happen. When a task finishes, say so in a status message or a Toast.
- Filled segments meet 3:1 against the ground and the empty segments in every theme.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-progress-segment-height | -height-sm | -gap | -radius | -empty
- --flux-progress-fill | -fill-warning | -fill-error
- --flux-progress-header-gap | -label | -value
Do and don’t
Do
- Change the value on the progress or meter element, not on the segments.
- Pick low, high and optimum from what the value means to the business, and write that meaning in the value text.
- Use the count of the real units as data-segments when it is small, such as one segment per room.
Don’t
- Do not colour a progress bar by status. Progress is not a warning; if a task fails, stop it and say why.
- Do not animate the segments filling in turn, or add a glow to the leading segment.
- Do not use a meter for completion over time, or a progress bar for a level.