Progress
Determinate bar showing completion of a task from 0 to 100. Built on Radix Progress. Height h-2 (8px), rounded-full, bg-muted track with a bg-primary indicator that slides in from the left.
Anatomy
- 1Progress (root)
Radix Root. Sets the visual size (h-2 w-full rounded-full) and the muted track surface.
- 2Indicator
The filled portion. bg-primary, rounded-full, driven by a translateX(-100 + value)% transform. Animates smoothly on value change.
- 3Percentage label (external)
Optional visible number rendered next to the bar. Radix does NOT render one for you — compose it in the parent for accessibility.
Variants
<Progress value={0} />
<Progress value={25} />
<Progress value={50} />
<Progress value={75} />
<Progress value={100} />Radix animates value changes via transition-transform out of the box.
States
Progress is stateless in shape but visually maps a value 0-100. Empty (0), partial (1-99), and complete (100) all use the same primary indicator. For failed / indeterminate states use Alert, Skeleton or a spinner respectively.
<Progress value={0} />
<Progress value={62} />
<Progress value={100} />Recipes
Ready-to-copy compositions covering the most common Yuno usages of this atom.
Label + filename left, percentage right, Progress bar full-width below. The canonical pattern for uploads (import CSV, avatar, attachments).
<div className="grid gap-2 w-full max-w-md">
<div className="flex items-center justify-between text-sm">
<span className="text-foreground inline-flex items-center gap-2">
<FileArrowUp weight="light" className="size-4 text-muted-foreground" />
report-2026-07.csv
</span>
<span className="text-muted-foreground">72%</span>
</div>
<Progress value={72} aria-label="Uploading report-2026-07.csv: 72%" />
</div>Progress bar with a status row below: 'Processing 12,340 of 20,000 rows · ~2 min left'. Use for long-running backend jobs where the user needs reassurance.
<div className="grid gap-2 w-full max-w-md">
<div className="flex items-center justify-between text-sm">
<span className="text-foreground">Import transactions</span>
<span className="text-muted-foreground">62%</span>
</div>
<Progress value={62} />
<div className="text-xs text-muted-foreground">
Processing 12,340 of 20,000 rows · ~2 min left
</div>
</div>Progress inside a Card as a quota meter (API usage, rule allocation). Big number on top, label + Progress below, remaining amount right.
<div className="rounded-lg border bg-card p-5 w-full max-w-sm">
<div className="text-xs text-muted-foreground">API usage</div>
<div className="mt-1 text-2xl font-semibold text-foreground">
62,340 <span className="text-sm font-normal text-muted-foreground">/ 100,000</span>
</div>
<div className="mt-3 grid gap-2">
<Progress value={62} aria-label="API usage: 62%" />
<div className="flex items-center justify-between text-xs text-muted-foreground">
<span>Resets Jul 30</span>
<span>37,660 remaining</span>
</div>
</div>
</div>Progress bar pinned at the top of a wizard-style flow. Value = (currentStep / totalSteps) * 100. Pair with 'Step X of N' text.
<div className="grid gap-3 w-full">
<div className="flex items-center justify-between text-sm">
<span className="font-medium text-foreground">Create rule</span>
<span className="text-muted-foreground">Step 2 of 4</span>
</div>
<Progress value={50} aria-label="Wizard progress: step 2 of 4" />
<div className="flex justify-between">
<Button variant="outline" size="sm">Back</Button>
<Button size="sm">Continue</Button>
</div>
</div>Import
Copy this import line at the top of the file where you compose this atom.
import { Progress } from "@/components/ui/progress";Props
Everything else from the underlying HTML or Radix primitive is forwarded via ...props.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | 0 | Current completion, 0-100. Radix animates the indicator via transition-transform on change. |
| max | number | 100 | Upper bound for value. Rarely changed — keeps value as a percentage. |
| aria-label / aria-labelledby | string | — | Required for accessibility. Describe what the bar tracks (e.g. 'Uploading report.csv: 72%'). |
| className | string | — | Merged onto the root. Default is h-2 w-full rounded-full bg-muted. Do not tint the bar destructive/warning by default. |
When to use
- Uploads, imports, or any measurable operation.
- Meters inside cards (rule health, allocation, quota).
- Multi-step wizard headers showing overall progress.
- Long-running backend jobs where the user is waiting.
When not to use
- Indeterminate loading — use Skeleton or a spinner.
- Step-by-step wizards where the current step matters more than the ratio — use Tabs or a stepper.
- Success / error signaling — use Badge, Alert or Toast.
Usage
- Always render the percentage as text alongside the bar for accessibility and reassurance.
- Keep the value between 0 and 100.
- Animate value changes — Radix does this via transition-transform out of the box.
- Pair with an aria-label or aria-labelledby that describes what the bar tracks.
- Don't tint the bar destructive/warning by default — the bar is neutral.
- Don't use Progress for indeterminate loading — the bar implies a measurable value.
- Don't rely on the bar alone — always pair with a visible label.
Related
Cross-links to atoms and patterns you may reach for next.