Skip to content
Components

Progress

A bar that shows how much of a task is done when the amount is known: an upload, an import, steps of a setup. With no value it shows that work runs without saying how much is left. label names the task above the bar, and showValue adds the percentage.

Preview

Uploading report.pdf

Props

  • value
  • max
  • size
  • showValue
  • label
import { Progress } from "@/components/ui/progress"

<Progress label="Uploading report.pdf" value={40} className="max-w-sm" />

Usage

When to use

  • Show how much of a task is done when the amount is known: an upload, an import, the files of a sync.
  • A task long enough for the user to wait on, named above the bar.

When not to use

  • Work whose amount is never known, such as checking a value. Use Spinner.
  • Content whose layout you know while it loads, such as a list. Use Skeleton.
  • The steps of a flow the user moves through, such as a setup wizard.

Variants

size

Thickness of the track: md on its own, sm inside a dense row or a card.

  • Uploading report.pdf

    sm

  • Uploading report.pdf

    mddefault

import { Progress } from "@/components/ui/progress"

<Progress label="Uploading report.pdf" value={40} size="sm" className="max-w-sm" />
<Progress label="Uploading report.pdf" value={40} className="max-w-sm" />

Examples

Upload

Uploading report.pdf
import { Progress } from "@/components/ui/progress"

<Progress label="Uploading report.pdf" value={40} showValue />

A count of files

max is the real count, so the bar and its percentage follow the files done.

Importing files
import { Progress } from "@/components/ui/progress"

<Progress label="Importing files" value={3} max={12} showValue />

Unknown amount

No value: the bar shows that work runs, not how much is left.

Preparing your export
import { Progress } from "@/components/ui/progress"

<Progress label="Preparing your export" />

Named elsewhere

A small bar in a card row whose name is already on screen.

import { Progress } from "@/components/ui/progress"

<Progress size="sm" aria-label="Storage sync" value={75} />

Do and don't

Do

  • Name the task in the label, and use the real count as max (12 files) when there is one.
  • Show the percentage when the task takes long enough for the user to wait on it.
  • Say in text when a long task is done or has failed; the bar alone is not announced.

Don't

  • Don't use it when the amount is never known. Use Spinner.
  • Don't show one bar per step of a single task; one bar covers the whole task.
  • Don't use it for the steps of a flow the user moves through.

Props

NameTypeValuesDefaultDescription
valuenumber--How much is done, from 0 to max. Leave it out, or pass null, when the amount is unknown: the bar is indeterminate.
maxnumber-100The value when the task is done. Use the real count (12 files) and pass the count done as value.
sizeenumsm | mdmdThickness of the track: md on its own, sm inside a dense row or a card.
labelnode--The visible name above the bar: what is in progress, Uploading report.pdf. Without it, set aria-label or aria-labelledby.
showValueboolean-falseShows the percentage at the end of the label row. Screen readers get it either way.

Anatomy

PartDescription
rootThe track: the soft gray fill, radius-full, the full width of its parent. 4px (sm) or 8px (md) thick.
indicatorThe accent fill from the start, as long as the share of the work that is done. With no value, a third of the track in the middle (so it never reads as an amount) that pulses.
wrapperWith label or showValue: the column that holds the label row above the track, gap-xs.
headerThe label row: the label, then the percentage at the end, gap-sm.
label13px medium primary text that names the task.
valueWith showValue: 13px secondary text with tabular figures, at the end of the label row.

Accessibility

Role: progressbar

  • Always named: the label prop (linked with aria-labelledby), or aria-label or aria-labelledby when the name is shown elsewhere. The type requires one.
  • aria-valuenow, aria-valuemin and aria-valuemax follow value and max; aria-valuetext reads the percentage (40%). With no value, the bar is indeterminate and has neither.
  • The visible percentage (showValue) is hidden from screen readers, since they read aria-valuetext on the bar.
  • The fill grows only when the user allows motion, and the indeterminate pulse stops under prefers-reduced-motion.
  • A progress bar is not a live region. For a long task, also say in text when it is done.

Install

npx shadcn add https://werewolf-ui.vercel.app/r/progress.json

This also adds styles/werewolf.css, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after @import "tailwindcss", with a path relative to that CSS file (from app/globals.css it is @import "../styles/werewolf.css").