Componentform0.8 KB gzipZero dependencies

Form Progress

Form completion progress with segmented dashed bars.

Preview

Live Preview
Completed3/5 · %60

Installation

Tokens guide →

Add to your project via CLI (zero dependencies, code you own):

npx bigbullui add form-progress

Or install the full npm package:

npm install bigbullui
import { FormProgress } from "@/components/ui/form-progress";

<FormProgress />

Usage guidance

Use Form Progress when a ticket stub surface needs Form completion progress with segmented dashed bars. Keep props minimal and prefer composition with sibling stubs.

Avoid Form Progress for long form flows or dense data grids where a dedicated layout block fits better.

Source code

form-progress.tsx

Zero dependencies (only React + utils). Copy and paste directly into your project:

"use client";

import * as React from "react";
import { cn } from "./lib/utils";

export interface FormProgressProps extends React.HTMLAttributes<HTMLDivElement> {
  total: number;
  completed: number;
  label?: string;
}

/** Form completion progress bar: segmented steps + percentage. */
export function FormProgress({ total, completed, label = "Completed", className, ...props }: FormProgressProps) {
  const pct = Math.min(100, Math.round((completed / Math.max(1, total)) * 100));

  return (
    <div className={cn("w-full", className)} {...props}>
      <style>{`@keyframes fpFill { from { transform: scaleX(0); } }`}</style>
      <div className="flex items-center justify-between font-mono text-[10px] uppercase tracking-[0.15em] text-muted-foreground">
        <span>{label}</span>
        <span className="tabular-nums">{completed}/{total} · %{pct}</span>
      </div>
      <div className="mt-1.5 flex gap-1" role="progressbar" aria-valuenow={pct} aria-valuemin={0} aria-valuemax={100} aria-label={label}>
        {Array.from({ length: total }).map((_, i) => (
          <div
            key={i}
            className={cn(
              "h-1.5 flex-1 origin-left rounded-full border border-dashed transition-colors duration-300 motion-reduce:transition-none",
              i < completed ? "border-accent/60 bg-accent" : "border-border bg-transparent"
            )}
            style={i < completed ? { animation: "fpFill 0.4s cubic-bezier(0.16,1,0.3,1) both", animationDelay: `${i * 60}ms` } : undefined}
          />
        ))}
      </div>
    </div>
  );
}

Props

PropTypeDescription
totalnumber
completednumber
labelstring