shadcn.io is not affiliated with official shadcn/ui
The bar fills from a number your code already has. It doesn't watch the request for you.
Use it for an upload or a numbered step when people should see how much is left. If there is nothing to measure, use a Spinner. In React, Base UI draws the bar and can leave it indeterminate when you do not know the end.
Installation
Anatomy

Progress
├── ProgressLabel
├── ProgressTrack
├── ProgressIndicator
├── ProgressValue
├── ProgressView
└── ProgressCircle
├── ProgressCircleTrack
└── ProgressCircleRangeUsage
import { useEffect, useState } from "react";
import { Progress } from "@/components/ui/progress";const ProgressDemo = () => {
const [progress, setProgress] = useState(13);
useEffect(() => {
const timer = setTimeout(() => setProgress(66), 500);
return () => clearTimeout(timer);
}, []);
return <Progress className="w-[60%]" value={progress} />;
};Demos
Label
ProgressLabel names the bar, here an upload, and ProgressValue prints the percent beside it. Both sit in Progress and follow value. Use them when a bare bar on the page could be any of several tasks. The label also names the bar for assistive tech, so you can skip a separate aria-label when the visible word is the right name.
Controlled
The bar only displays value. A Slider writes that number here so you can drag and watch the fill, which is a stand-in for the real source. In the app, the number comes from the upload or from the step you are on, and the bar will not subscribe to a request. Use a controlled value whenever the task can report how far it has gotten.
Rtl
dir set to rtl puts the Arabic caption and the percent on a right-to-left row. The number is the same value. Use this to check a translated page, not as a variant you render only for one language. Set dir on Progress when this bar should follow a right-to-left parent even if you have not flipped the whole document.
FAQ
How do I update the Progress value in React?
Pass value and change it as the work advances: Progress shows the number you give it and doesn't watch your request. For an upload, set it from the request's progress events; for a multi-step task, set it per step.
The Controlled demo above drives it from a Slider.
How do I show an indeterminate Progress bar when I don't know how long it will take?
Pass null as value: the bar reports an indeterminate state instead of a percentage.
If there's nothing to measure at all, a Spinner says "working" more honestly than an empty bar.
How do I count steps instead of percent with the Base UI Progress?
Set min and max on Progress (0 and 100 by default), then pass value in the same units, such as 3 with a max of 5 for the third of five steps.
How do I change what screen readers hear for the Base UI Progress?
Pass getAriaValueText for the text, and format with Intl.NumberFormat options for the shown value.
How do I show a label and the percentage next to the Progress bar?
Add ProgressLabel for the name and ProgressValue for the number inside Progress, as in the Label demo above. The value text follows value, and the label names the bar for screen readers too.
When should I use a Slider or a Circular Progress instead of a Progress bar?
Progress only displays a value. If people should set the number, use a Slider; for a ring in a small space, use Circular Progress; and for work with no measurable amount, use a Spinner.
API Reference
Progress
<div> data-slot="progress"
valuenumber | null
The current value. The component is indeterminate when value is null.
- Type
number | null
format?Intl.NumberFormatOptions
Options to format the value.
getAriaValueText?(formattedValue: string, value: number | null) → string
Accepts a function which returns a string value that provides a human-readable text alternative for the current value of the progress bar.
- Type
(formattedValue: string, value: number | null) → string- Parameters
formattedValue– stringvalue– number | null- Returns
string
locale?Intl.LocalesArgument
The locale used by Intl.NumberFormat when formatting the value.
Defaults to the user's runtime locale.
- Default
"en-US"
max?number
The maximum value.
- Default
100
min?number
The minimum value.
- Default
0
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
ProgressLabel
<span> data-slot="progress-label"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
ProgressTrack
<div> data-slot="progress-track"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
ProgressIndicator
<div> data-slot="progress-indicator"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
ProgressRange
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
ProgressValue
<span> data-slot="progress-value"
children?null | ((formattedValue: string | null, value: number | null) → React.ReactNode)
A function that gets formattedValue and returns what it renders.
- Type
null | ((formattedValue: string | null, value: number | null) → React.ReactNode)
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.