Skip to content

ProgressBar

<caos-progress-bar>

determinate or staged progress for a long operation

May be placed on a record page, an app’s home page, a page inside an app and a step of a guided flow.

Name Attribute Description Type Default Required
value value, markup only How far along, on the min–max scale. It is clamped to that range, and a value that will not parse falls back to min. Ignored entirely while indeterminate is set. number 0 Optional
min min, markup only The bottom of the scale — an empty track. number 0 Optional
max max, markup only The top of the scale — a full track. Set it to the real total (files, rows, dollars) and pass the raw count as the value rather than converting to a percentage first. number 100 Optional
indeterminate indeterminate, markup only This is running and there is no honest number to give. Slides a segment along the track, drops aria-valuenow, and blanks the percentage readout. boolean false Optional
label label, markup only The visible caption above the track, which also becomes the bar’s accessible name. Unset, the caption line is not drawn at all. text none declared Optional
showValue show-value, markup only Print the percentage at the right-hand end of the caption line, rounded to a whole number. It is always a PERCENTAGE of the min–max span, never the raw value, so a bar counting 0–2400 rows still reads “62%”. boolean false Optional
intent intent, markup only The fill colour: accent, success, warning or danger. The accent moves with a tenant’s brand; the three semantic ones do not. text — one of accent, success, warning, danger accent Optional
variant variant, markup only The SHAPE the same measurement takes: a horizontal bar, or a ring. Everything else is unchanged by it — the value, the bounds, the intent colours, the indeterminate state and its reduced-motion fallback, and what a screen reader is told. A ring is not a different component measuring the same thing; it is this one drawn round. With show-value, the percentage moves into the middle of the ring, which is the only place it reads as belonging to it. text — one of bar, circular bar Optional

This piece raises no events.

Nothing goes inside this piece.

Design token What it controls
--caos-color-surface-2 The unfilled track, and the unfilled part of the ring.
--caos-color-accent The default fill, and the stripes of the reduced-motion fallback.
--caos-color-success The fill when intent is success.
--caos-color-warning The fill when intent is warning.
--caos-color-danger The fill when intent is danger.
--caos-radius-pill The rounded ends of the track and the fill.
--caos-color-text The caption.
--caos-color-text-muted The percentage readout.
--caos-font The typeface of the caption and the readout.
--caos-space-3 The gap between the caption and the readout.
--caos-space-2 The gap between the caption line and the track.

Nothing else drives this piece by calling it.

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(bar) the whole block, header and track Always
::part(header) the label-and-value line above the track Always
::part(label) the label text Always
::part(value) the value text Always
::part(track) the groove Always
::part(fill) the filled part of the groove Always
::part(ring) the circle the progress is drawn on Always present as a part; it is only drawn while the variant is circular.

One operation that takes long enough for somebody to wonder whether it is still going. Use the determinate form whenever a real fraction is available and the indeterminate form when it is not — inventing a number to avoid the indeterminate state is how a bar ends up sitting at 90%.

  • SkeletonBlock — A surface is LOADING and there is no operation to report on. The skeleton says “content is coming and this is the shape of it”; a bar says “a job is running and here is how far”.
  • Button — The wait belongs to the control that started it and is short. The button’s own loading flag draws a spinner and marks itself busy, which is the whole story for a save.
  • Toast — The operation has FINISHED and the outcome is what wants saying.
  • StatTile — The number is a figure to read rather than progress towards a finish. A bar implies something is moving and will end.

The element is a role="progressbar" and keeps aria-valuemin, aria-valuemax and aria-valuenow in step with what is drawn, so the percentage on screen and the percentage announced cannot disagree; label is mirrored to the accessible name. The indeterminate state REMOVES aria-valuenow rather than reporting zero, and its animation is replaced — not merely stopped — under prefers-reduced-motion: reduce, so nobody is left looking at a track that seems stalled. Left to the author: giving it a label (a bar with no name is announced as a bare percentage), and not relying on the fill colour alone to say that something went wrong.

The ordinary case: a caption, a fill at 62% of the scale, and the readout — the number drawn and the number announced are the same one.

{
"id": "example",
"section": "A job with a number",
"columns": 1,
"items": [
{
"id": "progress_bar_1",
"type": "component",
"key": "progress_bar",
"inputs": {
"value": 62,
"label": "Importing records",
"show_value": true
}
}
]
}
<caos-progress-bar value="62" label="Importing records" show-value></caos-progress-bar>

Running with nothing honest to report: a segment slides along the track, the readout is blank, and aria-valuenow is dropped rather than reported as zero.

{
"id": "example",
"section": "A job with no number",
"columns": 1,
"items": [
{
"id": "progress_bar_1",
"type": "component",
"key": "progress_bar",
"inputs": {
"indeterminate": true,
"label": "Waiting for the report to build"
}
}
]
}
<caos-progress-bar indeterminate label="Waiting for the report to build"></caos-progress-bar>

The same element under prefers-reduced-motion: reduce — the slide is replaced by a static stripe rather than simply removed, so it still reads as running. Turn the setting on and this is what the example above becomes.

{
"id": "example",
"section": "The same job, reduced motion",
"columns": 1,
"items": [
{
"id": "progress_bar_1",
"type": "component",
"key": "progress_bar",
"inputs": {
"indeterminate": true,
"label": "Waiting for the report to build"
}
}
]
}
<caos-progress-bar indeterminate label="Waiting for the report to build"></caos-progress-bar>

Every fill colour on the same value, so a bar used as a gauge — a quota nearly spent, a budget overrun — can be coloured by what the number means.

{
"id": "example",
"section": "The four fills",
"columns": 1,
"items": [
{
"id": "progress_bar_1",
"type": "component",
"key": "progress_bar",
"inputs": {
"value": 62,
"label": "Default (brand accent)",
"show_value": true
}
},
{
"id": "progress_bar_2",
"type": "component",
"key": "progress_bar",
"inputs": {
"value": 62,
"intent": "success",
"label": "Success",
"show_value": true
}
},
{
"id": "progress_bar_3",
"type": "component",
"key": "progress_bar",
"inputs": {
"value": 62,
"intent": "warning",
"label": "Warning",
"show_value": true
}
},
{
"id": "progress_bar_4",
"type": "component",
"key": "progress_bar",
"inputs": {
"value": 62,
"intent": "danger",
"label": "Danger",
"show_value": true
}
}
]
}
<caos-progress-bar value="62" label="Default (brand accent)" show-value></caos-progress-bar>
<caos-progress-bar value="62" intent="success" label="Success" show-value></caos-progress-bar>
<caos-progress-bar value="62" intent="warning" label="Warning" show-value></caos-progress-bar>
<caos-progress-bar value="62" intent="danger" label="Danger" show-value></caos-progress-bar>