Progress

Displays an indicator showing the completion progress of a task.

The Progress component displays a visual indicator of task completion. It shows progress as a percentage with a smooth animated fill. Built from scratch using React and native HTML elements. No dependencies on any UI library.

Code

TypeScript: Copy this code into components/ui/progress.tsx:

tsx
"use client"

import * as React from "react"
import { cn } from "@/lib/utils"

interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
  value?: number
  max?: number
}

const Progress = React.forwardRef<HTMLDivElement, ProgressProps>(
  ({ className, value = 0, max = 100, ...props }, ref) => {
    const percentage = Math.min(Math.max((value / max) * 100, 0), 100)

    return (
      <div
        ref={ref}
        className={cn(
          "relative h-4 w-full overflow-hidden rounded-full border-2 border-foreground bg-background",
          className
        )}
        role="progressbar"
        aria-valuenow={value}
        aria-valuemin={0}
        aria-valuemax={max}
        {...props}
      >
        <div
          className="h-full bg-primary transition-all duration-300 ease-in-out"
          style={{ width: `${percentage}%` }}
        />
      </div>
    )
  }
)
Progress.displayName = "Progress"

export { Progress }

JavaScript: Copy this code into components/ui/progress.jsx:

jsx
"use client"

import * as React from "react"
import { cn } from "@/lib/utils"

const Progress = React.forwardRef(
  ({ className, value = 0, max = 100, ...props }, ref) => {
    const percentage = Math.min(Math.max((value / max) * 100, 0), 100)

    return (
      <div
        ref={ref}
        className={cn(
          "relative h-4 w-full overflow-hidden rounded-full border-2 border-foreground bg-background",
          className
        )}
        role="progressbar"
        aria-valuenow={value}
        aria-valuemin={0}
        aria-valuemax={max}
        {...props}
      >
        <div
          className="h-full bg-primary transition-all duration-300 ease-in-out"
          style={{ width: `${percentage}%` }}
        />
      </div>
    )
  }
)
Progress.displayName = "Progress"

export { Progress }

Usage

TypeScript:

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

function MyComponent() {
  return <Progress value={33} />
}

JavaScript:

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

function MyComponent() {
  return <Progress value={33} />
}

Make sure you also have the lib/utils.ts file with the cn helper function.

Examples

Default

50% Progress

75% Progress

100% Progress

Animated

Progress: 33%