Skip to Content
Hashti Design System
Components

Progress Circle

Circular radial meter communicating progress or activity within compact spaces.

Progress Circle

The Progress Circle communicates progress or system activity within tight, circular spaces—such as inside table cells, card corners, file upload rows, and modal dialogs.

Like its linear sibling, Progress Circle supports both determinate percentage rings and continuous indeterminate spinners, rendering sharp SVG geometry scaled for high-density enterprise interfaces.

Progress CircleRadial loading spinner with precise stroke geometry.

Import

import { ProgressCircle } from "@hashti/react";

Examples

Determinate Progress

Provide a value between minValue (default 0) and maxValue (default 100) to render a radial progress stroke:

import { ProgressCircle } from "@hashti/react";

export function DeterminateCircleExample() {
  return (
    <div className="flex items-center gap-6">
      <ProgressCircle aria-label="Exporting archives" value={25} />
      <ProgressCircle aria-label="Encrypting data" value={60} />
      <ProgressCircle aria-label="Optimization complete" value={100} />
    </div>
  );
}

Indeterminate Loading Spinner

When the duration or size of an operation is unknown, set isIndeterminate to activate a continuous rotation animation:

import { ProgressCircle } from "@hashti/react";

export function IndeterminateCircleExample() {
  return (
    <div className="flex items-center gap-6">
      <ProgressCircle aria-label="Loading workspace contents" isIndeterminate />
      <span className="text-sm text-subtle">Synchronizing repository...</span>
    </div>
  );
}

Sizes

Progress Circle is available in three standard diameters:

  • sm: 32px (with 2.5px stroke), ideal for inline badges, buttons, and high-density tables.
  • md: 48px (with 3.5px stroke, default), standard for cards and widgets.
  • lg: 64px (with 4.5px stroke), prominent for hero cards and standalone loading screens.
import { ProgressCircle } from "@hashti/react";

export function ProgressCircleSizesExample() {
  return (
    <div className="flex items-center gap-8">
      <div className="text-center">
        <ProgressCircle size="sm" value={45} aria-label="Small progress circle" />
        <p className="mt-2 text-xs text-subtle">Small (32px)</p>
      </div>

      <div className="text-center">
        <ProgressCircle size="md" value={65} aria-label="Medium progress circle" />
        <p className="mt-2 text-xs text-subtle">Medium (48px)</p>
      </div>

      <div className="text-center">
        <ProgressCircle size="lg" value={85} aria-label="Large progress circle" />
        <p className="mt-2 text-xs text-subtle">Large (64px)</p>
      </div>
    </div>
  );
}

Showing Value Labels

Set showValueLabel to render the percentage value centered directly inside the circle:

import { ProgressCircle } from "@hashti/react";

export function CenteredLabelExample() {
  return (
    <div className="flex items-center gap-8">
      <ProgressCircle size="md" value={50} showValueLabel aria-label="Download 50% complete" />

      <ProgressCircle size="lg" value={78} showValueLabel aria-label="Processing 78% complete" />
    </div>
  );
}

Status Variants

Use the status prop to convey semantic state (active, success, warning, error):

import { ProgressCircle } from "@hashti/react";

export function CircleStatusesExample() {
  return (
    <div className="flex items-center gap-6">
      <ProgressCircle status="active" value={60} aria-label="Active backup" />
      <ProgressCircle status="success" value={100} aria-label="Backup completed" />
      <ProgressCircle status="warning" value={88} aria-label="Storage capacity warning" />
      <ProgressCircle status="error" value={42} aria-label="Pipeline failure" />
    </div>
  );
}

Props Reference

PropTypeDefaultDescription
valuenumber0The current numeric progress value.
minValuenumber0The minimum possible progress boundary.
maxValuenumber100The maximum possible progress boundary.
isIndeterminatebooleanfalseWhether to display a continuous rotational loading animation.
size'sm' | 'md' | 'lg''md'The diameter of the circular meter: sm (32px), md (48px), or lg (64px).
status'active' | 'success' | 'warning' | 'error''active'Semantic color applied to the active progress stroke.
showValueLabelbooleanfalseWhen true, renders the formatted percentage string centered inside the circle.
aria-labelstring—Recommended: Accessible name announced by screen readers describing the in-flight process.
classNamestring—Additional CSS class names.

Accessibility (a11y)

  • Progressbar Semantics: Inherits React Aria Components’ native role="progressbar" implementation.
  • Accessible Labelling: Because circular indicators often omit a visible text heading, always supply an aria-label (e.g. aria-label="Downloading assets") or aria-labelledby pointing to an adjacent descriptive title.
  • Value Announcements: Screen readers dynamically read aria-valuenow, aria-valuemin, and aria-valuemax as values update.
  • Decorative SVGs: The internal SVG element is marked with aria-hidden="true", preventing screen readers from vocalizing unnecessary geometric path or circle tags.

WAI-ARIA & Data Attributes

AttributeTargetDescription
[data-indeterminate]ProgressCirclePresent when circular spinner is in continuous spin mode.