Installation
pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/progress.jsonInstalls to @/components/ui/progress.
Manual installation
Install the dependencies:
pnpm add @base-ui/react@^1.8.0Copy the source into your project:
'use client'
import { Progress as ProgressPrimitive } from '@base-ui/react/progress'
import { cn } from '@/lib/utils'
function Progress({
className,
children,
value = null,
...props
}: Omit<ProgressPrimitive.Root.Props, 'value'> & {
/** The current value (0–`max`). Leave it out or pass `null` for an indeterminate progress bar. */
value?: number | null
}) {
return (
<ProgressPrimitive.Root
value={value}
data-slot="progress"
className={cn('flex flex-wrap gap-3', className)}
{...props}
>
{children}
<ProgressTrack>
<ProgressIndicator />
</ProgressTrack>
</ProgressPrimitive.Root>
)
}
function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
return (
<ProgressPrimitive.Track
className={cn('relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-secondary', className)}
data-slot="progress-track"
{...props}
/>
)
}
function ProgressIndicator({ className, ...props }: ProgressPrimitive.Indicator.Props) {
return (
<ProgressPrimitive.Indicator
data-slot="progress-indicator"
className={cn('h-full bg-primary transition-all', className)}
{...props}
/>
)
}
function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
return (
<ProgressPrimitive.Label className={cn('text-sm font-medium', className)} data-slot="progress-label" {...props} />
)
}
function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
return (
<ProgressPrimitive.Value
className={cn('ml-auto text-sm text-muted-foreground tabular-nums', className)}
data-slot="progress-value"
{...props}
/>
)
}
export { Progress, ProgressTrack, ProgressIndicator, ProgressLabel, ProgressValue }A progress component built on top of Base UI Progress, providing an accessible way to display progress or loading state.
Features
- Built on the Base UI Progress primitive (
@base-ui/reactpackage) - Slim
h-1track onbg-secondarywith abg-primaryindicator by default - Optional
ProgressLabelandProgressValuechildren, which label the bar and show the formatted value - Indeterminate when
valueis left out ornull - Smooth transitions between values
- Height and colors customizable via
className - Screen reader support (
role="progressbar")
Usage
Give every progress bar an accessible name with aria-label or aria-labelledby.
import { Progress, ProgressLabel, ProgressValue } from '@/components/ui/progress'
// Basic usage
export function BasicProgress() {
return <Progress value={40} aria-label="Application progress" />
}
// With a visible label and value; ProgressLabel names the progress bar
export function LabelledProgress() {
return (
<Progress value={40}>
<ProgressLabel>Applicant details</ProgressLabel>
<ProgressValue />
</Progress>
)
}
// With custom height (default is h-1): className goes on the root, so target the track
export function CustomSizeProgress() {
return <Progress value={60} aria-label="Upload progress" className="*:data-[slot=progress-track]:h-2" />
}
// With a custom indicator colour (use theme tokens)
export function CustomColorProgress() {
return (
<Progress value={80} aria-label="Places filled" className="**:data-[slot=progress-indicator]:bg-chart-2" />
)
}
// Animated progress
export function AnimatedProgress() {
const [progress, setProgress] = React.useState(0)
React.useEffect(() => {
const timer = setInterval(() => {
setProgress((prev) => (prev >= 100 ? 0 : prev + 10))
}, 500)
return () => clearInterval(timer)
}, [])
return <Progress value={progress} aria-label="Archive transfer" />
}Examples
Default
Progress through a five-step e-service, labelled with aria-labelledby.
With Animation
The value changes after a short delay and the indicator slides smoothly.
Different Sizes
The default h-1 track, then h-2 and h-3 via className="*:data-[slot=progress-track]:h-2".
Custom Colors
Preschool capacity with indicators coloured from the chart-1 to chart-4 tokens.
With Label
File uploads for a building permit, each with its own progress and status text.
Loading Animation
A long-running archive transfer with a continuous progress loop.
Props
Progress
value- The current progress value (0-100); leave it out or passnullfor an indeterminate barmin/max- The range (defaults 0 and 100)className- Additional CSS classes (applied to the root, a wrapping flex container; target the track with*:data-[slot=progress-track]:…and the indicator with**:data-[slot=progress-indicator]:…)format/locale-Intl.NumberFormatoptions and locale for the value textgetAriaValueText-(formattedValue, value) => string, the text read by screen readerschildren- Rendered before the track, typicallyProgressLabelandProgressValue
ProgressLabel, ProgressValue, ProgressTrack, ProgressIndicator
ProgressLabel- A visible label that names the progress bar (aria-labelledby)ProgressValue- The formatted value, e.g.40%ProgressTrack/ProgressIndicator- The partsProgressrenders, exported for custom layouts
Accessibility
The Progress component follows WAI-ARIA guidelines:
- Uses the
progressbarrole - Provides the value through
aria-valuenowandaria-valuetext(a formatted percentage by default) - Includes
aria-valueminandaria-valuemax - Supports custom value text with
getAriaValueText - Screen readers do not announce value changes on their own; use a status message (a polite live region) for milestones such as "Upload complete"
- Every progress bar needs a name:
aria-label,aria-labelledbyor aProgressLabel
Best Practices
-
Values:
- Use 0-100 range for consistency
- Handle edge cases (null, undefined)
- Consider decimal precision
- Validate input values
-
Visual Design:
- Maintain sufficient contrast
- Use appropriate sizes
- Consider color meaning
- Provide clear visual feedback
-
Animation:
- Use smooth transitions
- Avoid excessive animations
- Consider reduced motion
- Handle interruptions
-
Accessibility:
- Provide meaningful labels
- Test with screen readers
- Consider color blindness
- Maintain ARIA attributes
-
Implementation:
- Handle loading states
- Consider performance
- Test edge cases
- Maintain responsiveness
Related Components
- Slider
- Spinner
- Skeleton