Circular Progress

Loading

Circular ring progress indicator.

Preview

Usage

example.jsx
import { CircularProgress } from "@/components/ui/circular-progress";

export default function Example() {
  return <CircularProgress />;
}

Source Code

Copy this file into components/ui/circular-progress.jsx in your project.

circular-progress.jsx
import { forwardRef } from "react";
import { cn } from "@/lib/utils";

const CircularProgress = forwardRef(({ className, value = 0, size = 48, strokeWidth = 4, showLabel, ...props }, ref) => {
  const radius = (size - strokeWidth) / 2;
  const circumference = 2 * Math.PI * radius;
  const offset = circumference - (value / 100) * circumference;

  return (
    <div ref={ref} className={cn("relative inline-flex items-center justify-center", className)} {...props}>
      <svg width={size} height={size} className="-rotate-90">
        <circle cx={size / 2} cy={size / 2} r={radius} fill="none" strokeWidth={strokeWidth} className="stroke-muted" />
        <circle cx={size / 2} cy={size / 2} r={radius} fill="none" strokeWidth={strokeWidth} strokeLinecap="round"
          strokeDasharray={circumference} strokeDashoffset={offset}
          className="stroke-primary transition-all duration-500"
        />
      </svg>
      {showLabel && <span className="absolute text-xs font-medium">{Math.round(value)}%</span>}
    </div>
  );
});
CircularProgress.displayName = "CircularProgress";

export { CircularProgress };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge