Skip to content
Lenso UI

ProgressCircle

A circular progress indicator that shows determinate or indeterminate progress.

Usage

import { ProgressCircle } from '@lenso/ui';
"use client";
import { ProgressCircle } from "@lenso/ui";
export function Basic() {  return (    <ProgressCircle aria-label="Loading" value={60}>      <ProgressCircle.Track>        <ProgressCircle.TrackCircle />        <ProgressCircle.FillCircle />      </ProgressCircle.Track>    </ProgressCircle>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Anatomy

import { ProgressCircle } from '@lenso/ui';
export default () => (  <ProgressCircle aria-label="Loading" value={60}>    <ProgressCircle.Track>      <ProgressCircle.TrackCircle />      <ProgressCircle.FillCircle />    </ProgressCircle.Track>  </ProgressCircle>);

Examples

Sizes

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressCircle } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 24 } });export function Sizes() {  return (    <div {...stylex.props(styles.row)}>      {(        [          ["sm", 40],          ["md", 60],          ["lg", 80],        ] as const      ).map(([size, value]) => (        <ProgressCircle key={size} aria-label="Loading" size={size} value={value}>          <ProgressCircle.Track>            <ProgressCircle.TrackCircle />            <ProgressCircle.FillCircle />          </ProgressCircle.Track>        </ProgressCircle>      ))}    </div>  );}export default Sizes;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Colors

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressCircle } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 24 } });export function Colors() {  return (    <div {...stylex.props(styles.row)}>      {(["default", "accent", "success", "warning", "danger"] as const).map((color) => (        <ProgressCircle key={color} aria-label={color} color={color} value={60}>          <ProgressCircle.Track>            <ProgressCircle.TrackCircle />            <ProgressCircle.FillCircle />          </ProgressCircle.Track>        </ProgressCircle>      ))}    </div>  );}export default Colors;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Indeterminate

Use isIndeterminate when progress cannot be determined.

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0); null is Base UI's indeterminate value.import { ProgressCircle } from "@lenso/ui";export function Indeterminate() {  return (    <ProgressCircle aria-label="Loading" value={null}>      <ProgressCircle.Track>        <ProgressCircle.TrackCircle />        <ProgressCircle.FillCircle />      </ProgressCircle.Track>    </ProgressCircle>  );}export default Indeterminate;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

With Label

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0); the label belongs to the progress context.import { ProgressCircle } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 12 } });export function WithLabel() {  return (    <ProgressCircle xstyle={styles.row} value={75}>      <ProgressCircle.Track>        <ProgressCircle.TrackCircle />        <ProgressCircle.FillCircle />      </ProgressCircle.Track>      <ProgressCircle.Label>75% Complete</ProgressCircle.Label>    </ProgressCircle>  );}export default WithLabel;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Custom SVG Props

Since each part is a composable component, you can override SVG attributes like strokeWidth, r, cx, cy, and viewBox directly.

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressCircle } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ row: { display: "flex", alignItems: "flex-end", gap: 24 } });export function CustomSvg() {  return (    <div {...stylex.props(styles.row)}>      <ProgressCircle aria-label="Thin circle" value={60}>        <ProgressCircle.Track strokeWidth={2} viewBox="0 0 36 36">          <ProgressCircle.TrackCircle cx={18} cy={18} r={17} strokeWidth={2} />          <ProgressCircle.FillCircle cx={18} cy={18} r={17} strokeWidth={2} />        </ProgressCircle.Track>      </ProgressCircle>      <ProgressCircle aria-label="Default circle" value={60}>        <ProgressCircle.Track>          <ProgressCircle.TrackCircle />          <ProgressCircle.FillCircle />        </ProgressCircle.Track>      </ProgressCircle>      <ProgressCircle aria-label="Thick circle" value={60}>        <ProgressCircle.Track strokeWidth={6} viewBox="0 0 36 36">          <ProgressCircle.TrackCircle cx={18} cy={18} r={15} strokeWidth={6} />          <ProgressCircle.FillCircle cx={18} cy={18} r={15} strokeWidth={6} />        </ProgressCircle.Track>      </ProgressCircle>    </div>  );}export default CustomSvg;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Customization

Tailwind CSS

"use client";// Adapted from HeroUI v3.2.6 (Apache-2.0).import { ProgressCircle } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  track: { width: 56, height: 56 },  background: { stroke: "light-dark(oklch(92.2% 0 0), oklch(26.9% 0 0))" },  fill: { stroke: "light-dark(oklch(37.1% 0 0), oklch(87% 0 0))" },});export function CustomStyles() {  return (    <ProgressCircle aria-label="Sync progress" value={68}>      <ProgressCircle.Track xstyle={styles.track}>        <ProgressCircle.TrackCircle xstyle={styles.background} />        <ProgressCircle.FillCircle xstyle={styles.fill} strokeLinecap="round" />      </ProgressCircle.Track>    </ProgressCircle>  );}export default CustomStyles;

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Global CSS

To customize the ProgressCircle component classes, you can use the @layer components directive. Learn more.

@layer components {  .progress-circle {    @apply inline-flex;  }
  .progress-circle__track {    @apply size-12;  }
  .progress-circle__fill-circle {    stroke: purple;  }}

Styling Reference

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The ProgressCircle component uses these CSS classes (View source styles):

Base & Element Classes [!toc]

  • .progress-circle - Base container
  • .progress-circle__track - SVG element
  • .progress-circle__track-circle - Background circle
  • .progress-circle__fill-circle - Progress arc

Size Classes [!toc]

  • .progress-circle--sm - Small size variant
  • .progress-circle--md - Medium size variant (default)
  • .progress-circle--lg - Large size variant

Color Classes [!toc]

  • .progress-circle--default - Default color variant
  • .progress-circle--accent - Accent color variant
  • .progress-circle--success - Success color variant
  • .progress-circle--warning - Warning color variant
  • .progress-circle--danger - Danger color variant

API Reference

ProgressCircle

Inherits from React Aria ProgressBar.

PropTypeDefaultDescription
valuenumber0The current value
minValuenumber0The minimum value
maxValuenumber100The maximum value
isIndeterminatebooleanfalseWhether progress is indeterminate
size"sm" | "md" | "lg""md"Size of the circle
color"default" | "accent" | "success" | "warning" | "danger""accent"Color of the progress arc
formatOptionsIntl.NumberFormatOptions{style: 'percent'}Number format for the value display
childrenReactNode | (values: ProgressBarRenderProps) => ReactNode-Content or render prop

Render Props

When using the render prop pattern, these values are provided:

PropTypeDescription
percentagenumberThe percentage of the progress (0-100)
valueTextstringThe formatted value text
isIndeterminatebooleanWhether progress is indeterminate