CoreUI is in beta - APIs and components may change.
CoreUI
Base Components

Progress Circle

A progress circle is a simple chart that can be used to show how complete something is.


50%

Installation

Create a progress-circle.tsx file and paste the following code into it.

components/ui/progress-circle.tsx
// CoreUI ProgressCircle v0.0.0import * as React from 'react';import { cn } from '@/utils/cn';import { tv, type VariantProps } from '@/utils/tv';export const progressCircleVariants = tv({  slots: {    text: '',  },  variants: {    size: {      '80': { text: 'text-label-sm' },      '72': { text: 'text-label-sm' },      '64': { text: 'text-label-sm' },      '56': { text: 'text-label-xs' },      '48': { text: 'text-label-xs' },      '44': { text: 'text-label-xs' },    },  },  defaultVariants: {    size: '80',  },});function getSizes({  size,}: Pick<VariantProps<typeof progressCircleVariants>, 'size'>) {  switch (size) {    case '80':      return {        strokeWidth: 6.4,        radius: 40,      };    case '72':      return {        strokeWidth: 5.75,        radius: 36,      };    case '64':      return {        strokeWidth: 5.1,        radius: 32,      };    case '56':      return {        strokeWidth: 4.5,        radius: 28,      };    case '48':      return {        strokeWidth: 6.7,        radius: 24,      };    case '44':      return {        strokeWidth: 5.5,        radius: 22,      };    default:      return {        strokeWidth: 6.4,        radius: 40,      };  }}type ProgressCircleRootProps = Omit<React.SVGProps<SVGSVGElement>, 'value'> &  VariantProps<typeof progressCircleVariants> & {    value?: number;    max?: number;    children?: React.ReactNode;    color?: string;  };const ProgressCircleRoot = React.forwardRef<  SVGSVGElement,  ProgressCircleRootProps>(  (    {      value = 0,      max = 100,      size,      className,      children,      color = 'stroke-primary-base',      ...rest    }: ProgressCircleRootProps,    forwardedRef,  ) => {    const { text } = progressCircleVariants({ size });    const { strokeWidth, radius } = getSizes({ size });    const safeValue = Math.min(max, Math.max(value, 0));    const normalizedRadius = radius - strokeWidth / 2;    const circumference = normalizedRadius * 2 * Math.PI;    const offset = circumference - (safeValue / max) * circumference;    return (      <>        <div className={cn('relative', className)}>          <svg            ref={forwardedRef}            width={radius * 2}            height={radius * 2}            viewBox={`0 0 ${radius * 2} ${radius * 2}`}            className='-rotate-90'            role='progressbar'            aria-valuenow={value}            aria-valuemin={0}            aria-valuemax={max}            {...rest}          >            <circle              r={normalizedRadius}              cx={radius}              cy={radius}              strokeWidth={strokeWidth}              fill='none'              className='stroke-bg-soft-200'            />            {safeValue >= 0 && (              <circle                r={normalizedRadius}                cx={radius}                cy={radius}                strokeWidth={strokeWidth}                strokeDasharray={`${circumference} ${circumference}`}                strokeDashoffset={offset}                fill='none'                className={`${color} transition-all duration-300 ease-out`}              />            )}          </svg>          {children && (            <div              className={text({                class:                  'absolute inset-0 flex items-center justify-center text-center',              })}            >              {children}            </div>          )}        </div>      </>    );  },);ProgressCircleRoot.displayName = 'ProgressCircleRoot';export { ProgressCircleRoot as Root };

Examples

Size

0%
25%
50%
75%
100%
0%
25%
50%
75%
100%
0%
25%
50%
75%
100%
0%
25%
50%
75%
100%

API Reference

ProgressCircle.Root

The main component of the ProgressCircle. It displays a circular progress indicator with a customizable size and color. This component is based on the <svg> element and supports all of its props and adds:

PropTypeDefault
size"80" | "72" | "64" | "56" | "48" | "44""80"
valuenumber
maxnumber100
childrenReact.ReactNodeundefined

On this page