Skip to content

Documentation

neelam-ui

Search documentation

Getting Started
Forms
Overlays
Navigation
Data Display
Layout
AI & Chat
Blocks
GitHub repository

Progress

A track with a filled portion showing how far along something is — or a pulsing bar when the duration is unknown.

Uploading — 62%
Indeterminate

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#

Keyboard shortcuts
KeyBehaviour
TabNot focusable. Progress reports state; it is not a control. For a draggable value, see Resizable's handle.

Accessibility#

  • role="progressbar" with aria-valuemin, aria-valuemax, and aria-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#

Props for Progress
PropTypeDefault
max

The value that represents 100% complete. Defaults to `100`.

number100
value

Current 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.