Progress

A progress bar used to show the completion status of an ongoing operation.

Docs
Loading
65%
import { Progress, ProgressLabel, ProgressTrack, ProgressValueText } from "~/components/progress";

export default function ProgressBasicDemo() {
  return (
    <Progress value={65} class="space-y-2">
      <ProgressLabel>Loading</ProgressLabel>
      <ProgressTrack />
      <ProgressValueText />
    </Progress>
  );
}

Installation

CLI

Run the following command to add the component to your project:

npx @ark-preset/cli@latest add progress

Manual

Create the recipe file at src/components/recipes/progress.ts:

import { tv, type VariantProps } from "tailwind-variants";

export const progressVariants = tv({
  slots: {
    root: "relative w-full",
    track: "h-2 w-full overflow-hidden rounded-full bg-muted",
    range:
      "h-full w-full flex-1 bg-primary transition-all data-[state=indeterminate]:animate-progress-indeterminate",
    valueText: "text-base md:text-sm font-medium tabular-nums text-muted-foreground",
    view: "",
  },
});

export type ProgressVariants = VariantProps<typeof progressVariants>;

Create the component directory and files.

src/components/progress/progress.base.tsx:

import { Progress as ArkProgress } from "@ark-ui/solid/progress";
import { splitProps, type Component } from "solid-js";
import { progressVariants, labelVariants } from "../recipes/progress";

const styles = progressVariants();

const Root: Component<ArkProgress.RootProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.Root class={styles.root({ class: local.class })} {...others} />;
};

const RootProvider: Component<ArkProgress.RootProviderProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.RootProvider class={styles.root({ class: local.class })} {...others} />;
};

const Label: Component<ArkProgress.LabelProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.Label class={labelVariants({ class: local.class })} {...others} />;
};

const Track: Component<ArkProgress.TrackProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.Track class={styles.track({ class: local.class })} {...others} />;
};

const Range: Component<ArkProgress.RangeProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.Range class={styles.range({ class: local.class })} {...others} />;
};

const ValueText: Component<ArkProgress.ValueTextProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.ValueText class={styles.valueText({ class: local.class })} {...others} />;
};

const View: Component<ArkProgress.ViewProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ArkProgress.View class={styles.view({ class: local.class })} {...others} />;
};

const Circle = ArkProgress.Circle;
const CircleRange = ArkProgress.CircleRange;
const CircleTrack = ArkProgress.CircleTrack;

export const Progress = {
  Root,
  RootProvider,
  Label,
  Track,
  Range,
  ValueText,
  View,
  Circle,
  CircleRange,
  CircleTrack,
};

src/components/progress/index.tsx:

import { splitProps, type Component } from "solid-js";
import { Progress as ProgressBase } from "./progress.base";
import { Progress as ArkProgress } from "@ark-ui/solid/progress";

const Progress = ProgressBase.Root;
const ProgressRootProvider = ProgressBase.RootProvider;
const ProgressLabel = ProgressBase.Label;
const ProgressValueText = ProgressBase.ValueText;

// Composite wrappers — auto-include sub-parts
const ProgressTrack: Component<ArkProgress.TrackProps> = (props) => {
  const [local, others] = splitProps(props, ["children"]);
  return (
    <ProgressBase.Track {...others}>
      <ProgressBase.Range />
      {local.children}
    </ProgressBase.Track>
  );
};

export {
  Progress,
  ProgressRootProvider,
  ProgressLabel,
  ProgressTrack,
  ProgressValueText,
  ProgressBase,
};

export { progressVariants, type ProgressVariants } from "../recipes/progress";

Note: Make sure your project has the Tailwind CSS theme variables set up (--background, --foreground, --ring, --border, etc.) or override the utility classes to match your design system.

Usage

Basic Usage

Loading
65%
import { Progress, ProgressLabel, ProgressTrack, ProgressValueText } from "~/components/progress";

export default function ProgressBasicDemo() {
  return (
    <Progress value={65} class="space-y-2">
      <ProgressLabel>Loading</ProgressLabel>
      <ProgressTrack />
      <ProgressValueText />
    </Progress>
  );
}

Indeterminate

Omit the value prop to render an indeterminate progress bar:

Loading...
import { Progress, ProgressLabel, ProgressTrack } from "~/components/progress";

export default function ProgressIndeterminateDemo() {
  return (
    <Progress>
      <ProgressLabel>Loading...</ProgressLabel>
      <ProgressTrack />
    </Progress>
  );
}

API Reference

See the Ark UI Progress documentation.