Skip to main content

Progress

A progress bar shows how much of a task is done. Pass a value for a determinate bar; leave it out (or pass null) when the amount of work is unknown and the indicator sweeps the track instead. The track is always --muted; the fill takes a semantic colour.

import Progress from '@zuilib/components/progress'

Determinate and indeterminate

value is clamped to 0..max. A determinate indicator slides with a transform so updates animate cheaply; an indeterminate one is a third of the track sweeping across it (a pulse under prefers-reduced-motion).

Loading example

Variants

Loading example

Sizes

Track heights step with --spacing (h-1, h-2, h-3); the value label steps with the type scale.

Loading example

Custom max and format

max sets aria-valuemax (aria-valuemin is always 0). formatValue produces both the visible label and aria-valuetext, so a unit-based format is announced as such. Use aria-labelledby when a visible heading names the bar.

Loading example

Props

ProgressProps extends the <div> attributes (minus children and role) with:

PropTypeDefaultDescription
valuenumber | nullCurrent value, clamped to 0..max. null / undefined renders indeterminate
maxnumber100Must be finite and positive; anything else falls back to 100
size'sm' | 'md' | 'lg''md'Track height h-1 / h-2 / h-3
variant'primary' | 'success' | 'warning' | 'destructive''primary'Fill colour; the track is always --muted
showValuebooleanfalseRenders the formatted value beside the bar (determinate only)
formatValue(value: number, max: number) => stringwhole percentageUsed for the visible label and aria-valuetext
aria-labelstringAccessible name for a self-contained bar. One of aria-label / aria-labelledby is required (typed)
aria-labelledbystringId of a visible heading or label that names the bar
classNamestringMerged last onto the root

Slots

SlotElementNotes
[data-slot="progress"]divRoot, role="progressbar". Also data-state="determinate" | "indeterminate", data-variant, data-size
[data-slot="progress-track"]divClips the indicator; mirrored under dir="rtl"
[data-slot="progress-indicator"]divThe fill (transform) or the sweeping third
[data-slot="progress-label"]spanThe formatted value; aria-hidden. Present with showValue on a determinate bar
/* Consumer CSS: square track and fill */
[data-slot="progress-track"],
[data-slot="progress-indicator"] {
border-radius: 0;
}

Tokens

TokenUsed for
--mutedTrack
--primary, --success, --warning, --destructiveFill per variant
--muted-foregroundValue label
--spacing, --text-xs/sm/baseTrack height and label size per size
--duration-normalFill transition
--animate-progress-indeterminateIndeterminate sweep

Accessibility

  • Root is role="progressbar" with aria-valuemin={0}, aria-valuemax, aria-valuenow (omitted while indeterminate) and aria-valuetext from formatValue.
  • Indeterminate bars set aria-busy="true".
  • A name is required: aria-label or aria-labelledby. The types enforce one of the two; a development-only console warning fires when neither reaches the DOM.
  • The visible value label is aria-hidden; aria-valuenow / aria-valuetext already announce it.
  • Motion: the fill transition and the sweep are disabled under prefers-reduced-motion (the sweep becomes a pulse).
  • Direction-aware: under dir="rtl" the fill anchors to the right edge and the sweep runs right-to-left.