Progress Bar

A thin bar that reports a quantity, or sweeps when there is none to report. Two modes, one element.

API

Props

proptypedefault
as?ElementType"div"the element or component to render
mode?ProgressBarMode"indeterminate"determinate reports value, indeterminate sweeps
value?number0percentage, clamped between 0 and 100
animate?booleantruewhen false, value changes are not transitioned
fill?stringthe primary gradientanything a background accepts: a colour, a gradient
className?stringmerged over the defaults, so it wins

Examples

Usage

tsx
<ProgressBar mode="determinate" value={uploaded} />
<ProgressBar />
previewdeterminate at 30 and 70, then indeterminate

Details

The two modes

In determinate mode the fill is clipped to the percentage, and the clip transitions, so a value that moves reads as motion rather than as a jump. The value is clamped between 0 and 100, so an out of range number is a harmless bug instead of a broken bar.

In indeterminate mode — the default — a segment sweeps back and forth forever. It says only that something is happening, which is why it belongs to waits with no measurable end.

Accessibility follows the mode

The element is always a progressbar, but only determinate mode carries aria-valuenow with its minimum and maximum. Indeterminate deliberately carries none: an unknown quantity is announced by the absence of a value, not by a zero.

Fill and animation

fill takes anything a background accepts — a flat colour, another gradient, a token — and the component writes it into its own custom property. The default lives in the signature, so the gradient is discoverable from the props table rather than from the stylesheet.

tsx
<ProgressBar mode="determinate" value={62} fill="var(--margo-color-on-main)" />

animate set to false removes the transition on the clip, which is what you want when the value comes from a scroll position or a drag: there the number is already continuous, and a transition would make it lag behind the input.

tsx
<ProgressBar mode="determinate" value={value} animate={false} />

Not the navigation bar

This component reports a real quantity or an honest unknown. Route changes are neither: they have no measurable progress, but a sweeping bar reads as a stalled page. That is what NavigationBar is for — it simulates an approach that never reaches the end, then completes.