Flux 2.0

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.

Not this
Not when the amount of work is unknown; use a Spinner. Not for a value without a range, such as a booking total; write the number. Not as a chart of several values side by side; use a chart.

Examples

Progress

A percentage, written by the script from the progress element when the value span has data-flux-percent.

81%
html
<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.

120 of 480
html
<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.

44 of 49, guaranteed
30 of 49, 10 more to guarantee
12 of 49, below the minimum of 20
html
<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%.

ISK 4,050,000 of 5,000,000
html
<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.

35%
html
<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

PartDescription
HeaderThe label, a label element bound to the progress or meter, and the value as text.
ValueThe number in words or a percentage, in mono. It says what the colour says, so colour is never the only signal.
ElementA visually hidden progress or meter. It holds the value; change it there and the segments follow.
Segmentsflux-segments, aria-hidden. Twenty by default, or the count in data-segments; a segment fills once its whole share is reached.

API

NameKindDescription
flux-progressclassA task under way. Holds a progress element and a flux-segments row.
flux-meterclassA measurement in a range. Holds a meter element with min, max, low, high and optimum.
flux-progress--smclassThe small segment height, on either wrapper.
flux-segmentsclassThe segment row, aria-hidden. data-segments sets the count; twenty by default.
data-flux-percentattributeOn the value span: the script writes the percentage into it.
data-toneattributeOn flux-meter, set by the script from the meter’s region: warning when suboptimal, error when worse. Absent at optimum.

States

StateTreatment
EmptyNo segment is filled until the value is above the minimum.
PartialAny value above the minimum fills at least one segment, so started never reads as not started.
CompleteEvery segment is filled only at the maximum.
Meter regionsOptimum in brand teal, suboptimal in the pending colour, even less good in the error colour.

Keyboard

KeysAction
—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.