Upload Progress

Loading

File upload progress with percentage display.

Preview

Done
67%
23%

Usage

example.jsx
import { UploadProgress } from "@/components/ui/upload-progress";

export default function Example() {
  return <UploadProgress />;
}

Source Code

Copy this file into components/ui/upload-progress.jsx in your project.

upload-progress.jsx
"use client";

import { forwardRef } from "react";
import { cn } from "@/lib/utils";

const UploadProgress = forwardRef(({ className, fileName, progress = 0, status = "uploading", onCancel, ...props }, ref) => (
  <div ref={ref} className={cn("flex items-center gap-3 rounded-lg border p-3", className)} {...props}>
    <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
      <svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" /></svg>
    </div>
    <div className="flex-1 min-w-0">
      <div className="flex items-center justify-between text-sm">
        <span className="truncate font-medium">{fileName}</span>
        <span className="shrink-0 text-xs text-muted-foreground">
          {status === "complete" ? "Done" : status === "error" ? "Error" : `${Math.round(progress)}%`}
        </span>
      </div>
      <div className="mt-1.5 h-1.5 w-full overflow-hidden rounded-full bg-muted">
        <div className={cn("h-full rounded-full transition-all",
          status === "complete" ? "bg-green-500" : status === "error" ? "bg-red-500" : "bg-primary"
        )} style={{ width: `${progress}%` }} />
      </div>
    </div>
    {onCancel && status === "uploading" && (
      <button onClick={onCancel} className="shrink-0 text-muted-foreground hover:text-foreground">
        <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
      </button>
    )}
  </div>
));
UploadProgress.displayName = "UploadProgress";

export { UploadProgress };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge