Skip to content

Progress

Horizontal progress bar with determinate and indeterminate modes, drawn in hard-edged character cells by default. Uses native progressbar ARIA with value clamping and a terminal-inspired sliding animation for indeterminate state.

Preview

Installation

$pnpm exec dgadd add ui/progress
[Installs to]src/components/ui/progress[Item]ui/progress

dgadd is not public on npm yet. Until the first release, pack @diffgazer/add from the repository and install that tarball into this app, which is what puts dgadd on pnpm exec.

UI components require Tailwind CSS v4. Local copy mode imports src/styles/styles.css; package mode uses @diffgazer/ui CSS once packages are available.

Usage

tsx
import { Progress } from "@/components/ui/progress";export default function ProgressDefault() {  return (    <div className="flex flex-col gap-4 w-64">      <Progress value={60} aria-label="Upload progress" />      <Progress aria-label="Loading" />    </div>  );}

Examples

Variants

Preview

Sizes

Preview

Labeled with value text

Preview

API Reference

Progress

NameTypeDefaultDescription
valuenumberCurrent progress value (0-100). Omit for indeterminate mode.
maxnumber100Finite positive maximum for the progress bar. Invalid values are normalized to 100.
size"sm" | "md""md"Height of the progress bar track. "sm" renders as the continuous bar.
variant"cells" | "bar""cells""cells" cuts track and fill into hard-edged character cells. "bar" keeps the continuous rounded track for hairline-thin inline uses.
valueTextstringCustom text exposed through aria-valuetext for the current value.

Data attributes

AttributeApplies toValuesDescription
data-stateProgress"loaded" | "indeterminate"Determinate/indeterminate state for track and indicator styling.
data-variantProgress"cells" | "bar"Selects the cell mask or the continuous track.
data-sizeProgress"sm" | "md"Track height; "sm" suppresses the cell mask.

CSS variables

NameDefaultDescription
--progress-cell8pxWidth of one cell in the cells variant, including its gap.
--progress-gap1pxWidth of the knocked-out gap between two cells.

Accessibility

Notes

Indeterminate Mode

When value is undefined, the bar enters indeterminate mode with a sliding fill animation. The aria-valuenow attribute is omitted per WAI-ARIA spec.

Value Clamping

The value is clamped between 0 and max. Values outside this range are silently corrected. A NaN value is normalized to 0 before clamping. A non-finite, zero, or negative max is normalized to the default of 100 before ARIA values and fill width are calculated.

Cells vs Bar

variant="cells" (default) masks track and fill into --progress-cell wide cells, so Progress speaks the same quantity language as BlockBar. The mask lives on the root, so the cells stay phase-aligned as the fill grows and the leading edge fills them one by one. variant="bar" keeps the continuous rounded track for hairline-thin inline uses. size="sm" is a 4px track — below the useful cell threshold — so it renders as the continuous bar even under variant="cells".

Reduced Motion

The indeterminate animation respects prefers-reduced-motion: reduce. When active, the bar renders a static 40% fill, and the determinate fill stops animating its width.

Progress vs BlockBar

Progress is the pixel bar for task completion: role=progressbar, a solid fill, and an indeterminate mode for work with no known duration. BlockBar is the character-cell meter for a steady-state measurement (role=meter) — coverage, token budget, severity mix — drawn from filled/empty glyphs and stackable into colored segments. Reach for Progress when something is running, BlockBar when something is being measured.

Source

Install via CLI: pnpm exec dgadd add ui/progress.

Highlighted source loads after this disclosure opens. Browse the source repository.