Aura Design System

Circular Progress

Determinate progress drawn as a circle.

Preview

Loading...
import { CircularProgress } from "@/components/ui/CircularProgress";

export function CircularProgressDemo() {
  return <CircularProgress value={64} label="Upload" />;
}

Installation

Make sure that namespace is set in your component.json file. Namespace docs: Learn more about namespaces

pnpm dlx shadcn@latest add @aura/circular-progress

Manual

Copy and paste the class names utility into your utils/class-names.ts file.

import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Copy and paste the CircularProgress component into your components/ui/CircularProgress.tsx file.

"use client";

import * as React from "react";
import { cn } from "@/utils/class-names";

function CircularProgress({
  className,
  value = 0,
  max = 100,
  label = "Progress",
  ...props
}: React.ComponentProps<"div"> & {
  value?: number;
  max?: number;
  label?: string;
}) {
  const safeMax = max > 0 ? max : 100;
  const ratio = Math.min(1, Math.max(0, value / safeMax));
  const radius = 16;
  const circumference = 2 * Math.PI * radius;
  return (
    <div
      role="progressbar"
      aria-label={label}
      aria-valuemin={0}
      aria-valuemax={safeMax}
      aria-valuenow={Math.round(value)}
      data-slot="circular-progress"
      className={cn("relative inline-flex size-4 items-center justify-center", className)}
      {...props}
    >
      <svg viewBox="0 0 40 40" className="size-4 -rotate-90" aria-hidden="true">
        <circle cx="20" cy="20" r={radius} fill="none" strokeWidth="3" className="stroke-gray-4" />
        <circle
          cx="20"
          cy="20"
          r={radius}
          fill="none"
          strokeWidth="3"
          strokeLinecap="round"
          className="stroke-accent-9"
          strokeDasharray={circumference}
          strokeDashoffset={circumference * (1 - ratio)}
        />
      </svg>
      <span className="absolute text-xs text-gray-12">{Math.round(ratio * 100)}</span>
    </div>
  );
}

export { CircularProgress };