

<Preview name="ProgressWithValueExample" />

## Overview [#overview]

The `Progress` component shows completion for a task or operation. Use the linear progress component for standard flows, `ProgressCircle` for compact circular status, and `ProgressRadial` for gauge-style displays.

Progress tracks are surface-aware. The track lands four levels above its parent surface and the indicator uses the default brand fill.

## Usage [#usage]

```tsx
import {
  Progress,
  ProgressCircle,
  ProgressRadial,
  ProgressValue,
} from "@tilt-legal/cubitt-components/progress";
```

```tsx
<Progress value={45}>
  <ProgressValue />
</Progress>

<ProgressCircle value={75} showValue />

<ProgressRadial value={60} startAngle={180} endAngle={360} showValue />
```

## Examples [#examples]

### With Value [#with-value]

Show the formatted value under the linear progress track.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="ProgressWithValueExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import {
      Progress,
      ProgressValue,
    } from "@tilt-legal/cubitt-components/progress";

    export default function Example() {
      const [progress, setProgress] = useState(13);

      useEffect(() => {
        const timer = setTimeout(() => {
          setProgress(66);
        }, 500);

        return () => {
          clearTimeout(timer);
        };
      }, []);

      return (
        <div className="w-80 space-y-2">
          <Progress value={progress}>
            <ProgressValue />
          </Progress>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Sizes [#sizes]

Adjust the track height with `className`.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="ProgressSizesExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import { Progress } from "@tilt-legal/cubitt-components/progress";

    export default function Example() {
      const [progress, setProgress] = useState(13);

      useEffect(() => {
        const timer = setTimeout(() => {
          setProgress(66);
        }, 500);

        return () => {
          clearTimeout(timer);
        };
      }, []);

      return (
        <div className="w-80 space-y-6">
          <div className="space-y-2">
            <p className="text-fg-2 text-sm">Small</p>
            <Progress className="h-1" value={progress} />
          </div>
          <div className="space-y-2">
            <p className="text-fg-2 text-sm">Default</p>
            <Progress value={progress} />
          </div>
          <div className="space-y-2">
            <p className="text-fg-2 text-sm">Large</p>
            <Progress className="h-2.5" value={progress} />
          </div>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Animated [#animated]

Animate progress value changes over time.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="AnimatedProgressExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import {
      Progress,
      ProgressValue,
    } from "@tilt-legal/cubitt-components/progress";

    export default function Example() {
      const [progress, setProgress] = useState(0);

      useEffect(() => {
        const timer = setInterval(() => {
          setProgress((current) => (current >= 100 ? 0 : current + 10));
        }, 500);

        return () => {
          clearInterval(timer);
        };
      }, []);

      return (
        <div className="w-80 space-y-2">
          <Progress value={progress}>
            <ProgressValue />
          </Progress>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### With Status [#with-status]

Show contextual status text alongside progress changes.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="ProgressWithStatusExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import { Progress } from "@tilt-legal/cubitt-components/progress";

    function getStatusMessage(progress: number): string {
      if (progress < 5) return "Initializing download...";
      if (progress < 15) return "Setting up environment...";
      if (progress < 25) return "Connecting to server...";
      if (progress < 35) return "Verifying permissions...";
      if (progress < 50) return "Downloading core files...";
      if (progress < 65) return "Downloading assets...";
      if (progress < 80) return "Downloading dependencies...";
      if (progress < 90) return "Extracting files...";
      if (progress < 95) return "Validating integrity...";
      if (progress < 100) return "Finalizing installation...";
      return "Download complete!";
    }

    export default function Example() {
      const [downloadProgress, setDownloadProgress] = useState(0);

      useEffect(() => {
        const timer = setInterval(() => {
          setDownloadProgress((current) => {
            if (current >= 100) {
              return 0;
            }

            return current + Math.random() * 3 + 1;
          });
        }, 150);

        return () => {
          clearInterval(timer);
        };
      }, []);

      return (
        <div className="w-80 space-y-2">
          <div className="flex justify-between text-sm">
            <span>Workspace Setup</span>
            <span className="text-fg-2">{Math.round(downloadProgress)}%</span>
          </div>
          <Progress value={downloadProgress} />
          <div className="text-fg-2 text-xs">
            {getStatusMessage(downloadProgress)}
          </div>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Circular Progress [#circular-progress]

Show progress as a full circle with custom center content.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="ProgressCircleCPUExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import { ProgressCircle } from "@tilt-legal/cubitt-components/progress";

    export default function Example() {
      const [cpuUsage, setCpuUsage] = useState(0);

      useEffect(() => {
        const timer = setInterval(() => {
          setCpuUsage((current) => {
            const target =
              30 +
              Math.sin(Date.now() / 3000) * 20 +
              Math.random() * 15;

            return current + (target - current) * 0.1;
          });
        }, 100);

        return () => {
          clearInterval(timer);
        };
      }, []);

      return (
        <div className="flex flex-col items-center gap-3">
          <ProgressCircle size={80} strokeWidth={6} value={cpuUsage}>
            <div className="text-center">
              <div className="font-bold text-base">{Math.round(cpuUsage)}%</div>
              <div className="text-fg-2 text-xs">CPU</div>
            </div>
          </ProgressCircle>
          <span className="text-fg-2 text-xs">Processor Usage</span>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Radial Progress [#radial-progress]

Show progress as a partial arc with custom angles.

<Tabs items="['Preview', 'Code']">
  <Tab value="Preview">
    <Preview name="ProgressRadialUploadExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { useEffect, useState } from "react";
    import { ProgressRadial } from "@tilt-legal/cubitt-components/progress";

    export default function Example() {
      const [taskProgress, setTaskProgress] = useState(0);

      useEffect(() => {
        const timer = setInterval(() => {
          setTaskProgress((current) => {
            if (current >= 100) {
              return 0;
            }

            return current + Math.random() * 2 + 0.5;
          });
        }, 200);

        return () => {
          clearInterval(timer);
        };
      }, []);

      return (
        <div className="flex flex-col items-center gap-3">
          <ProgressRadial
            endAngle={360}
            size={80}
            startAngle={180}
            strokeWidth={5}
            value={taskProgress}
          >
            <div className="text-center">
              <div className="font-bold text-base">
                {Math.round(taskProgress)}%
              </div>
              <div className="text-fg-2 text-xs">Upload</div>
            </div>
          </ProgressRadial>
          <span className="text-fg-2 text-xs">Upload Status</span>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Progress [#progress]

The accessible linear progress root.

| Prop               | Type                                      | Default | Description                                                               |
| ------------------ | ----------------------------------------- | ------- | ------------------------------------------------------------------------- |
| `value`            | `number \| null`                          | —       | Current progress value. Use `null` for indeterminate progress.            |
| `min`              | `number`                                  | `0`     | The minimum value.                                                        |
| `max`              | `number`                                  | `100`   | The maximum value.                                                        |
| `getAriaValueText` | `(formatted, value) => string`            | —       | Function returning human-readable text for the current value.             |
| `aria-valuetext`   | `string`                                  | —       | String value that provides a user-friendly name for the current value.    |
| `locale`           | `Intl.LocalesArgument`                    | —       | Locale used by `Intl.NumberFormat` when formatting the value.             |
| `format`           | `Intl.NumberFormatOptions`                | —       | Number formatting options for the value.                                  |
| `className`        | `string \| (state) => string`             | —       | Classes applied to the progress track, commonly used for height.          |
| `render`           | `ReactElement \| (props) => ReactElement` | —       | Allows composing the root with another element. Receives props to spread. |
| `children`         | `ReactNode`                               | —       | Child elements, typically `ProgressValue`.                                |

### ProgressValue [#progressvalue]

Displays the formatted progress value for linear progress.

| Prop        | Type                                      | Description                                                                    |
| ----------- | ----------------------------------------- | ------------------------------------------------------------------------------ |
| `className` | `string \| (state) => string`             | CSS classes or function that returns classes based on component state.         |
| `render`    | `ReactElement \| (props) => ReactElement` | Allows composing the component with another element. Receives props to spread. |

### ProgressCircle [#progresscircle]

Circular progress indicator built with SVG.

| Prop                 | Type             | Default | Description                                                     |
| -------------------- | ---------------- | ------- | --------------------------------------------------------------- |
| `value`              | `number \| null` | `0`     | Progress value from 0 to 100. `null` and `0` are indeterminate. |
| `size`               | `number`         | `48`    | Size of the circle in pixels.                                   |
| `strokeWidth`        | `number`         | `4`     | Width of the progress stroke.                                   |
| `showValue`          | `boolean`        | `false` | Whether to show the percentage value in the center.             |
| `indicatorClassName` | `string`         | —       | Additional className for the progress indicator stroke.         |
| `trackClassName`     | `string`         | —       | Additional className for the progress track.                    |
| `className`          | `string`         | —       | Additional CSS classes for the container.                       |
| `children`           | `ReactNode`      | —       | Custom content to display in the center. Overrides `showValue`. |

### ProgressRadial [#progressradial]

Radial progress indicator built with SVG.

| Prop                 | Type             | Default | Description                                                     |
| -------------------- | ---------------- | ------- | --------------------------------------------------------------- |
| `value`              | `number \| null` | `0`     | Progress value from 0 to 100. `null` and `0` are indeterminate. |
| `size`               | `number`         | `120`   | Size of the radial in pixels.                                   |
| `strokeWidth`        | `number`         | `8`     | Width of the progress stroke.                                   |
| `startAngle`         | `number`         | `-90`   | Start angle in degrees.                                         |
| `endAngle`           | `number`         | `90`    | End angle in degrees.                                           |
| `showValue`          | `boolean`        | `false` | Whether to show the percentage value in the center.             |
| `indicatorClassName` | `string`         | —       | Additional className for the progress indicator stroke.         |
| `trackClassName`     | `string`         | —       | Additional className for the progress track.                    |
| `className`          | `string`         | —       | Additional CSS classes for the container.                       |
| `children`           | `ReactNode`      | —       | Custom content to display in the center. Overrides `showValue`. |
