shadcn.io is not affiliated with official shadcn/ui
Shadcn Progress for React and Tailwind
Displays task progress with a linear indicator.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/progress.jsonpnpm dlx shadcn@latest add https://kit.dev/r/progress.jsonnpx shadcn@latest add https://kit.dev/r/progress.jsonyarn shadcn@latest add https://kit.dev/r/progress.jsonThis component depends on Field. Install it first if you haven't already.
Install the following dependencies:
bun add @ark-ui/reactpnpm add @ark-ui/reactnpm install @ark-ui/reactyarn add @ark-ui/reactAdd the following to your globals.css.
@theme inline {
--animate-indeterminate: indeterminate 1.5s ease-in-out infinite;
}
@keyframes indeterminate {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(400%);
}
}Copy and paste the following code into your project.
"use client";
import {
Progress as ArkProgress,
useProgressContext,
} from "@ark-ui/react/progress";
import type React from "react";
import { cn } from "@/lib/utils";
import { FieldLabel } from "@/components/ui/field";
export const useProgress = useProgressContext;
interface ProgressProps
extends Omit<React.ComponentProps<typeof ArkProgress.Root>, "value"> {
/**
* Shows indeterminate progress
*
* @default false
*/
indeterminate?: boolean;
/**
* The value of the progress bar
*
* @default 0
*/
value?: number;
}
export const Progress = (props: ProgressProps) => {
const {
value,
orientation = "horizontal",
indeterminate = false,
className,
children,
...rest
} = props;
return (
<ArkProgress.Root
className={cn(
"flex flex-wrap gap-3",
"data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:-scale-y-100",
className
)}
data-slot="progress"
orientation={orientation}
value={indeterminate ? null : value}
{...rest}
>
{children}
<ProgressTrack>
<ProgressRange />
</ProgressTrack>
</ArkProgress.Root>
);
};
export const ProgressTrack = (
props: React.ComponentProps<typeof ArkProgress.Track>
) => (
<ArkProgress.Track
className={cn(
"bg-input",
"rounded-full",
"overflow-x-hidden",
"data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2"
)}
data-slot="progress-track"
{...props}
/>
);
export const ProgressRange = (
props: React.ComponentProps<typeof ArkProgress.Range>
) => (
<ArkProgress.Range
className={cn(
"bg-primary",
"transition-all duration-300 ease-out",
"data-[orientation=horizontal]:h-full",
"data-[orientation=vertical]:h-full",
"motion-reduce:animate-none! motion-reduce:transition-none!",
"data-[state=indeterminate]:w-1/3 data-[state=indeterminate]:animate-indeterminate! data-[state=indeterminate]:duration-100"
)}
data-slot="progress-range"
{...props}
/>
);
export const ProgressValue = (
props: React.ComponentProps<typeof ArkProgress.ValueText>
) => {
const { className, ...rest } = props;
return (
<FieldLabel asChild>
<ArkProgress.ValueText
className={cn("ms-auto tabular-nums", className)}
data-slot="progress-value"
{...rest}
/>
</FieldLabel>
);
};Update the import paths to match your project setup.
Anatomy
Progress
├── ProgressLabel
├── ProgressTrack
├── ProgressRange
├── ProgressValue
├── ProgressView
└── ProgressCircle
├── ProgressCircleTrack
└── ProgressCircleRangeUsage
import React from "react";
import { Progress } from "@/components/ui/progress";const ProgressDemo = () => {
const [progress, setProgress] = React.useState(13);
React.useEffect(() => {
const timer = setTimeout(() => setProgress(66), 500);
return () => clearTimeout(timer);
}, []);
return <Progress className="w-full max-w-64" value={progress} />;
};Demos
Controlled
Indeterminate
Orientation Horizontal
Orientation Vertical
With Label
API Reference
Progress
div
PropType
AttributeType
ProgressTrack
div
PropType
AttributeType
ProgressRange
div
PropType
AttributeType
ProgressValue
span
PropType
AttributeType
useProgress
PropType