Progress Bar
A spring-tweened linear progress bar with a rolling percentage, an indeterminate sweep and buffer layer, and a single pulse with a check mark on reaching 100%.
A linear progress bar with some spring to it. When progress changes, the indicator springs to its new position and the percentage on the right rolls digit by digit. When the total is unknown, switch to indeterminate mode and a 40%-wide bar sweeps back and forth along the track; for video or streaming, add a buffer layer one shade lighter in the same colour. The moment progress goes from below max to max, the whole track pulses once, the right-hand text cross-fades into a check mark, and onComplete is called.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add progress-bar.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<ProgressBar/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/progress-bar.en.jsonOr, once registries are configured in components.json, install it as @webberui/progress-bar.
Usage
import { ProgressBar } from "@/components/ui/progress-bar";
<ProgressBar
value={uploaded}
max={total}
label="design-v3.fig"
showLabel
onComplete={() => console.log("Upload complete")}
/>
{/* Indeterminate */}
<ProgressBar indeterminate label="backup-archive.zip" />
{/* Video playback + buffer */}
<ProgressBar value={played} buffer={buffered} size="sm" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | null | 0 | Current progress (0..max, clamped); null is treated as indeterminate |
max | number | 100 | Maximum value |
indeterminate | boolean | false | Indeterminate mode: shows a back-and-forth sweep and omits aria-valuenow |
buffer | number | — | Buffered progress (0..max), drawn as a second bar in the same colour at 40% opacity |
showLabel | boolean | false | Show the percentage to the right of the track |
label | ReactNode | — | Top-left label text (e.g. a file name), also used as the progressbar's accessible name |
formatLabel | (percent: number) => string | — | Custom percentage text; when provided it renders as plain text without digit rolling |
size | "sm" | "md" | "lg" | "md" | Track height: sm 4px, md 8px, lg 12px |
color | string | — | Indicator colour; defaults to --wb-progress-bar-color (then the neutral scale) |
stiffness | number | 120 | Spring stiffness for the width and digit tweens |
damping | number | 20 | Spring damping for the width and digit tweens |
showComplete | boolean | true | Pulse once and swap the right-hand text for a check mark on reaching 100% |
onComplete | () => void | — | Called when progress goes from below max to max (fires again after dropping and refilling) |
className | string | — | Passed through to the outermost container |
How it works
- The indicator animates
scaleX(withtransform-origin: left) rather thanwidth, so the tween never triggers layout. - Digit rolling: each digit of the percentage is a 1em-tall
overflow: hiddencolumn holding a 0–9 stack, moved to the target by a springy; when the digit count changes (9% → 10%, 99% → 100%) the new digit fades in, andtabular-numskeeps the width steady. - The indeterminate bar is 40% wide and sweeps back and forth along the track over 1.4 seconds with easeInOut.
- The completion pulse fires once on the below-max → max transition; mounting already full does not pulse, while dropping and refilling fires it again.
- Colour: set the global CSS variable
--wb-progress-bar-colorto restyle every bar, and thecolorprop overrides it; the buffer layer's transition length reads--wb-progress-bar-durationon the root element (300ms by default).
Accessibility
- The root is
role="progressbar"witharia-valuemin,aria-valuemax,aria-valuenowandaria-valuetext(e.g. "42% complete"); indeterminate mode omitsaria-valuenow, setsaria-valuetextto "Processing" and setsaria-busy - With a
label,aria-labelledbypoints at it; without one it falls back toaria-label="Progress" - The rolling digits and the check mark are hidden from assistive tech; what gets announced comes from
aria-valuetext - When the user has reduce motion enabled: the indicator jumps into place without a spring, digits swap instantly, indeterminate mode becomes a static 40% bar that slowly breathes in opacity with a "Processing" label, and completion shows the check mark without the pulse
Alert Callout
An alert callout React component in five semantic variants that fades up on entry, collapses by height when dismissed so content below slides into place, and gives its icon a small pop when live content updates.
Spinner Set
Four React loading indicators — ring, dots, bars and a tracing brand mark — with adjustable size, speed and label, falling back to a static icon with text under reduced motion.