Progress
A track with a filled portion showing how far along something is — or a pulsing bar when the duration is unknown.
Usage#
import { Progress } from "neelam-ui";
<Progress value={62} aria-label="Upload progress" />value runs from 0 to max (default 100) and is clamped, so a value
outside the range cannot produce a bar wider than its track.
Indeterminate#
Omit value entirely and the bar pulses at full width instead of filling — for
work whose duration is not known:
<Progress aria-label="Loading" />aria-valuenow is left unset in this mode, which is exactly how assistive tech
distinguishes "in progress, amount unknown" from "0% done".
It needs a label#
A progressbar has no name from its content
Unlike a <button>, a role="progressbar" takes no name from what is inside
it — there is nothing inside it. Without aria-label or aria-labelledby,
axe flags aria-progressbar-name and a screen reader announces a bare
percentage with nothing to attach it to. Always pass one.
Say what is progressing, not that it is a progress bar: aria-label="Upload progress", not aria-label="Progress bar".
Why not <progress>#
Everywhere else this library styles the real native element. <progress> is an
exception alongside Select: its fill is drawn
inside vendor-prefixed pseudo-elements (::-webkit-progress-value,
::-moz-progress-bar) that render inconsistently across engines and cannot be
reached with a plain utility class. A track <div> with a width-driven fill
inside it is the one that can be styled consistently — so the ARIA is supplied
by hand instead.
Keyboard#
| Key | Behaviour |
|---|---|
| Tab | Not focusable. Progress reports state; it is not a control. For a draggable value, see Resizable's handle. |
Accessibility#
role="progressbar"witharia-valuemin,aria-valuemax, andaria-valuenow— the last omitted in indeterminate mode, which is what signals the unknown duration.- The value is clamped before it reaches
aria-valuenow, so the announced number can never exceed the maximum. - The indeterminate pulse and the determinate width transition are both dropped
under
prefers-reduced-motion. - Progress is not announced automatically as it changes. If completion matters — an upload finishing — announce that in a live region or move focus; a silently filling bar tells a screen reader user nothing.
Show the number too
Sighted users read a percentage far faster than they estimate a bar's width. The demo above puts "62%" in the visible label, which also gives the progressbar something meaningful to be labelled by.
API reference#
| Prop | Type | Default |
|---|---|---|
maxThe value that represents 100% complete. Defaults to `100`. | number | 100 |
valueCurrent progress, from `0` to `max`. Omitted (or `undefined`) renders an indeterminate/loading bar instead. | number | — |
Also accepts every native <div> attribute — and you should always pass one of
aria-label or aria-labelledby.