Github

Progress

Displays an indicator showing the completion progress of a task, typically as a progress bar.

x
"use client";

import * as React from "react";

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

export function ProgressDemo() {
	const [progress, setProgress] = React.useState(13);

	React.useEffect(() => {
		const timer = setTimeout(() => setProgress(66), 500);
		return () => clearTimeout(timer);
	}, []);

	return <Progress value={progress} className="w-[60%]" />;
}

Installation

pnpm dlx shadcn@latest add https://herocn.dev/r/progress.json

Usage

import {
  Progress,
  ProgressLabel,
  ProgressValue,
} from "@/components/ui/progress"
<Progress value={33} />

Composition

Use ProgressLabel and ProgressValue as optional children for a header row; the track and indicator are rendered automatically inside Progress.

Progress
├── ProgressLabel
├── ProgressValue
└── ProgressTrack
    └── ProgressIndicator

Examples

Label

Use ProgressLabel and ProgressValue to show a title and formatted percentage.

Upload progress
x
import {
	Progress,
	ProgressLabel,
	ProgressValue,
} from "@/components/ui/progress";

export function ProgressLabelExample() {
	return (
		<Progress value={56} className="w-full max-w-sm">
			<ProgressLabel>Upload progress</ProgressLabel>
			<ProgressValue />
		</Progress>
	);
}

Variants

Use the variant prop to match semantic status colors (default uses the neutral foreground on the track).

Default

x

Primary

x

Success

x

Warning

x

Destructive

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

export function ProgressVariants() {
	return (
		<div className="flex w-full max-w-sm flex-col gap-4">
			<div className="space-y-1">
				<p className="text-muted-foreground text-xs">Default</p>
				<Progress value={45} variant="default" className="w-full" />
			</div>
			<div className="space-y-1">
				<p className="text-muted-foreground text-xs">Primary</p>
				<Progress value={50} variant="primary" className="w-full" />
			</div>
			<div className="space-y-1">
				<p className="text-muted-foreground text-xs">Success</p>
				<Progress value={72} variant="success" className="w-full" />
			</div>
			<div className="space-y-1">
				<p className="text-muted-foreground text-xs">Warning</p>
				<Progress value={38} variant="warning" className="w-full" />
			</div>
			<div className="space-y-1">
				<p className="text-muted-foreground text-xs">Destructive</p>
				<Progress value={88} variant="destructive" className="w-full" />
			</div>
		</div>
	);
}

Sizes

Use the size prop to change the track height (sm, default, or lg).

Small
x
Default
x
Large
x
import {
	Progress,
	ProgressLabel,
	ProgressValue,
} from "@/components/ui/progress";

export function ProgressSizes() {
	return (
		<div className="flex w-full max-w-sm flex-col gap-6">
			<Progress value={40} size="sm" className="w-full">
				<ProgressLabel>Small</ProgressLabel>
				<ProgressValue />
			</Progress>
			<Progress value={55} size="default" className="w-full">
				<ProgressLabel>Default</ProgressLabel>
				<ProgressValue />
			</Progress>
			<Progress value={70} size="lg" className="w-full">
				<ProgressLabel>Large</ProgressLabel>
				<ProgressValue />
			</Progress>
		</div>
	);
}

Controlled

Drive the bar from another control, such as a slider.

x
"use client";

import * as React from "react";

import { Progress } from "@/registry/new-york-v4//ui/progress";
import { Slider } from "@/registry/new-york-v4//ui/slider";

export function ProgressControlled() {
	const [value, setValue] = React.useState(50);

	return (
		<div className="flex w-full max-w-sm flex-col gap-4">
			<Progress size="lg" value={value} className="w-full" />
			<Slider
				value={value}
				onValueChange={(value) => setValue(value as number)}
				min={0}
				max={100}
				step={1}
			/>
		</div>
	);
}

RTL

To enable RTL support in shadcn/ui, see the RTL configuration guide.

تقدم الرفع
x
"use client";

import {
	type Translations,
	useTranslation,
} from "@/components/language-selector";
import {
	Progress,
	ProgressLabel,
	ProgressValue,
} from "@/components/ui/progress";

const translations: Translations = {
	en: {
		dir: "ltr",
		values: {
			label: "Upload progress",
		},
	},
	ar: {
		dir: "rtl",
		values: {
			label: "تقدم الرفع",
		},
	},
	he: {
		dir: "rtl",
		values: {
			label: "התקדמות העלאה",
		},
	},
};

function toArabicNumerals(num: number): string {
	const arabicNumerals = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"];
	return num
		.toString()
		.split("")
		.map((digit) => arabicNumerals[Number.parseInt(digit, 10)] ?? digit)
		.join("");
}

export function ProgressRtl() {
	const { dir, t, language } = useTranslation(translations, "ar");

	const formatNumber = (num: number): string => {
		if (language === "ar") {
			return toArabicNumerals(num);
		}
		return num.toString();
	};

	return (
		<div className="w-full max-w-sm" lang={language} dir={dir}>
			<Progress value={56} className="w-full">
				<ProgressLabel>{t.label}</ProgressLabel>
				<ProgressValue>
					{(_formatted, value) => (
						<span className="ms-auto">{formatNumber(value ?? 0)}%</span>
					)}
				</ProgressValue>
			</Progress>
		</div>
	);
}

API Reference

Progress

Progress wraps Base UI Progress.Root and sets variant and size on the root for styling the built-in track and indicator.

PropTypeDefault

ProgressLabel

PropTypeDefault

ProgressValue

PropTypeDefault

ProgressTrack & ProgressIndicator

These parts are rendered by default. They are exported if you need to build a fully custom layout alongside the same primitives.

For the full root API (locale, getAriaValueText, etc.), see the Base UI Progress documentation.