Components

Circular Progress

Circular progress indicators with conic gradient glow effects

Circular Progress

Circular progress indicators featuring conic gradient glow effects and radial masking. Perfect for displaying loading states, completion percentages, and decorative background elements.

Usage

import { CircularProgress, CircularRing, ProgressRing, DualRing } from "@/components/ui/circular-progress";

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

Components

CircularProgress

The container component that provides radial masking and positioning for circular rings.

CircularRing

A decorative circular ring with conic gradient glow effect. Can be positioned and animated.

ProgressRing

An interactive progress indicator showing percentage completion with a conic gradient arc.

DualRing

Convenience component that renders two overlapping rings (Bento11 pattern).

Props

CircularProgress Props

PropTypeDefaultDescription
size"sm" | "default" | "lg""default"Container size
centeredbooleantrueCenter container horizontally

CircularRing Props

PropTypeDefaultDescription
size"sm" | "default" | "lg""default"Ring diameter
position"top" | "bottom" | "center""center"Vertical position
animatedbooleanfalseEnable rotation animation
opacity"full" | "medium" | "low""full"Glow opacity
rotationnumber0Initial rotation angle (degrees)

ProgressRing Props

PropTypeDefaultDescription
size"sm" | "default" | "lg""default"Ring size
valuenumber-Current progress value
maxnumber100Maximum value
showValuebooleantrueDisplay percentage text

DualRing Props

PropTypeDefaultDescription
topRotationnumber135Top ring rotation (degrees)
bottomRotationnumber0Bottom ring rotation (degrees)
topOpacity"full" | "medium" | "low""full"Top ring glow opacity
bottomOpacity"full" | "medium" | "low""low"Bottom ring glow opacity

Variants

Size Variants

// Small - 280px
<CircularProgress size="sm">
  <CircularRing />
</CircularProgress>

// Default - 336px
<CircularProgress size="default">
  <CircularRing />
</CircularProgress>

// Large - 400px
<CircularProgress size="lg">
  <CircularRing />
</CircularProgress>

Position Variants

// Top half
<CircularRing position="top" />

// Bottom half
<CircularRing position="bottom" />

// Centered
<CircularRing position="center" />

Examples

Animated Ring

<CircularProgress>
  <CircularRing animated />
</CircularProgress>

The ring rotates continuously with a 3.6s cycle using the button-glow animation.

Progress Indicator

import { useState } from "react";

export default function ProgressExample() {
  const [progress, setProgress] = useState(68);

  return (
    <ProgressRing value={progress} max={100} />
  );
}

Dual Ring Pattern (Bento11)

<DualRing 
  topRotation={135}
  bottomRotation={0}
  topOpacity="full"
  bottomOpacity="low"
/>

This recreates the exact Bento11 pattern with two overlapping rings.

Multiple Rings

<CircularProgress>
  <CircularRing position="top" rotation={135} opacity="full" />
  <CircularRing position="bottom" rotation={0} opacity="low" />
  <CircularRing position="center" rotation={270} opacity="medium" />
</CircularProgress>

Custom Rotation

<CircularRing rotation={45} />
<CircularRing rotation={90} />
<CircularRing rotation={180} />

With Content

<CircularProgress>
  <CircularRing animated />
  <div className="absolute inset-0 flex items-center justify-center z-10">
    <div className="text-center">
      <p className="text-4xl font-medium">68%</p>
      <p className="text-sm text-[var(--ui-text-secondary)]">Complete</p>
    </div>
  </div>
</CircularProgress>

Design Tokens

Dimensions

SizeDiameter
sm280px
default336px
lg400px

Effects

TokenValueDescription
Borderrgba(255, 255, 255, 0.15)Ring border
Glowvar(--gradient-conic-glow)Conic gradient from 180deg
Maskvar(--gradient-radial-center)Radial fade to transparent
Animationbutton-glow 3.6s linear infiniteRotation animation

Opacity Levels

LevelOpacityUse Case
full100%Primary ring
medium50%Secondary ring
low30%Background ring

Animation Details

The animated ring uses the button-glow keyframe animation defined in globals.css:

@keyframes button-glow {
  0% { transform: translateX(0) rotate(0); }
  25% { transform: translateX(-30px) rotate(90deg); }
  50% { transform: translateX(0) rotate(180deg); }
  75% { transform: translateX(30px) rotate(270deg); }
  100% { transform: translateX(0) rotate(360deg); }
}

Conic Gradient

The glow effect uses a conic gradient:

conic-gradient(
  from 180deg at 50% 50%,
  rgba(255, 255, 255, 0.01) 180deg,
  rgba(255, 255, 255, 0.05) 360deg
)

This creates a subtle rotating glow that appears to sweep around the ring.

Found In

  • Bento11 - Dual ring background with social icons
  • Bento14 - Single ring with avatar
  • Bento23 - Progress indicator
  • Bento24 - Loading state
  • Bento25 - Completion percentage

Accessibility

ProgressRing

  • Uses role="progressbar" for semantic meaning
  • Includes aria-valuenow, aria-valuemin, aria-valuemax
  • Percentage text is readable by screen readers
  • Visual progress is supplemented with text

CircularRing (Decorative)

  • Purely decorative background element
  • Does not interfere with content accessibility
  • Radial mask ensures content remains readable

Best Practices

// For loading states
<ProgressRing 
  value={progress} 
  aria-label="Upload progress"
/>

// For decorative backgrounds
<CircularProgress aria-hidden="true">
  <CircularRing animated />
</CircularProgress>

Performance

  • Pure CSS implementation for glow effect
  • Hardware-accelerated transforms
  • Single animation keyframe shared across all rings
  • Minimal DOM nodes (container + rings)
  • No JavaScript required for animation

On this page