Search

Jump to any page.

Feedback

Progress

Determinate bar with label and value, in four tones.

Tracing this week’s conversations
x
Channels connected
x
Evaluation coverage
x
pnpm dlx shadcn@latest add @paragon/progress
Brings in@base-ui/reactclass-variance-authoritycn
registry/paragon/ui/progress.tsx
"use client"

import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "cn"

const indicatorVariants = cva(
  "h-full rounded-full transition-[width] duration-(--duration-slower) ease-paragon motion-reduce:transition-none",
  {
    variants: {
      tone: {
        default: "bg-primary",
        brand: "bg-brand",
        fjord: "bg-fjord dark:bg-[#9db7dc]",
        oasis: "bg-oasis dark:bg-[#a8cf9f]",
      },
    },
    defaultVariants: {
      tone: "default",
    },
  }
)

/**
 * A determinate bar. Put a ProgressLabel and ProgressValue inside for the
 * caption row; the track wraps onto its own line beneath them.
 */
function Progress({
  className,
  children,
  value,
  tone,
  ...props
}: ProgressPrimitive.Root.Props & VariantProps<typeof indicatorVariants>) {
  return (
    <ProgressPrimitive.Root
      value={value}
      data-slot="progress"
      className={cn("flex w-full flex-wrap items-baseline gap-x-3 gap-y-2", className)}
      {...props}
    >
      {children}
      <ProgressTrack>
        <ProgressIndicator className={indicatorVariants({ tone })} />
      </ProgressTrack>
    </ProgressPrimitive.Root>
  )
}

function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
  return (
    <ProgressPrimitive.Track
      data-slot="progress-track"
      className={cn("relative flex h-1.5 w-full items-center overflow-hidden rounded-full bg-foreground/8", className)}
      {...props}
    />
  )
}

function ProgressIndicator({ className, ...props }: ProgressPrimitive.Indicator.Props) {
  return <ProgressPrimitive.Indicator data-slot="progress-indicator" className={cn(className)} {...props} />
}

function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
  return <ProgressPrimitive.Label data-slot="progress-label" className={cn("text-sm font-medium", className)} {...props} />
}

function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
  return (
    <ProgressPrimitive.Value
      data-slot="progress-value"
      className={cn("ms-auto text-sm text-muted-foreground tabular-nums", className)}
      {...props}
    />
  )
}

export { Progress, ProgressTrack, ProgressIndicator, ProgressLabel, ProgressValue }