Skip to content
Components

Progress

Communicates determinate completion or an indeterminate operation in progress.

Uploading assets64 / 100

Playground

value

Sets completed work before clamping to the valid range.

max

Sets the positive total used to calculate completion.

indeterminate

Makes this example pass a null value when completion is unknown.

scheme

Sets the indicator color.

Usage

tsx
import { Progress } from "earthling-ui/progress";

export function Example() {
  return (
    <>
      <Progress aria-label="Uploading assets" max={100} value={64} />
    </>
  );
}
  • Provide an accessible label that names the operation rather than repeating a percentage.
  • Set value to null for indeterminate work; finite values are clamped between zero and max.
  • Pair long-running progress with nearby text so completion remains understandable without color.

Installation

Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.

bash
npm install earthling-ui

Use the component import shown above. Package updates keep the implementation current.

API reference

Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.

tsx
// Generated by dts-bundle-generator v9.5.1

import * as ProgressPrimitive from '@radix-ui/react-progress';
import { VariantProps } from 'class-variance-authority';
import { ComponentPropsWithoutRef } from 'react';

export declare const progressVariants: (props?: ({
	scheme?: "default" | "primary" | "secondary" | "tertiary" | "neutral" | "muted" | "good" | "caution" | "bad" | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
export interface ProgressProps extends ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>, VariantProps<typeof progressVariants> {
}
export declare const Progress: import("react").ForwardRefExoticComponent<ProgressProps & import("react").RefAttributes<HTMLDivElement>>;

export {};

Runtime dependencies: @radix-ui/react-progress, class-variance-authority, cnfast.

Source

Use the eject command to copy this implementation with its required helpers and project-specific imports.

View Progress implementation
tsx
"use client";

import {
  type ComponentPropsWithoutRef,
  type ComponentRef,
  forwardRef,
} from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";

import { cn } from "@/utils/cn";
import { schemes } from "@/utils/variants";
import { cva, type VariantProps } from "class-variance-authority";

const progressVariants = cva(
  "relative h-2 w-full overflow-hidden rounded-full bg-muted",
  {
    variants: {
      scheme: schemes,
    },
    defaultVariants: { scheme: "default" },
  },
);

export interface ProgressProps
  extends
    ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>,
    VariantProps<typeof progressVariants> {}

const Progress = forwardRef<
  ComponentRef<typeof ProgressPrimitive.Root>,
  ProgressProps
>(({ className, value, max = 100, scheme, ...props }, ref) => {
  const normalizedMax = Number.isFinite(max) && max > 0 ? max : 100;
  const normalizedValue =
    value == null || !Number.isFinite(value)
      ? null
      : Math.min(Math.max(value, 0), normalizedMax);
  const percentage =
    normalizedValue === null ? null : (normalizedValue / normalizedMax) * 100;

  return (
    <ProgressPrimitive.Root
      ref={ref}
      value={normalizedValue}
      max={normalizedMax}
      className={cn(progressVariants({ scheme }), className)}
      {...props}
    >
      <ProgressPrimitive.Indicator
        className="h-full w-full bg-(--scheme-tint) transition-transform duration-300 ease-out data-[state=indeterminate]:w-1/2 data-[state=indeterminate]:translate-x-1/2 data-[state=indeterminate]:animate-pulse motion-reduce:animate-none motion-reduce:transition-none"
        style={
          percentage === null
            ? undefined
            : { transform: `translateX(-${100 - percentage}%)` }
        }
      />
    </ProgressPrimitive.Root>
  );
});
Progress.displayName = ProgressPrimitive.Root.displayName;

export { Progress, progressVariants };