Upload Progress
Per-file and aggregate progress bars for in-flight uploads, reading the ambient state of a useFiles instance.
A drop-in progress view. It reads the ambient uploads and progress a useFiles instance exposes, so it lights up for any upload that instance starts — wherever the call originates. Returns null when idle.
"use client";import { useFiles } from "files-sdk/react";import { UploadIcon } from "lucide-react";import type { ChangeEvent } from "react";import { useEffect, useRef } from "react";import { Button } from "@/components/ui/button";import { UploadProgress } from "@/components/files-sdk/upload-progress";const Example = () => { const files = useFiles({ endpoint: "/api/files" }); const inputRef = useRef<HTMLInputElement>(null); // Read `files` via a ref so this one-shot effect never re-runs on store // changes (see the file-list/file-preview note on the loop footgun). const filesRef = useRef(files); filesRef.current = files; // Kick off a sample upload on mount so the progress UI starts populated. useEffect(() => { const bytes = new Uint8Array(3 * 1024 * 1024); const sample = new File([bytes], "vacation-photo.jpg", { type: "image/jpeg", }); void filesRef.current.upload(sample); }, []); const handleChange = async (event: ChangeEvent<HTMLInputElement>) => { // Capture the element now — React nulls `currentTarget` after the handler's // synchronous phase, so it's gone by the time the uploads below resolve. const input = event.currentTarget; const picked = input.files; if (!picked?.length) { return; } for (const file of picked) { await files.upload(`demo/${file.name}`, file, { contentType: file.type, }); } input.value = ""; }; return ( <div className="flex flex-col gap-4"> <div> <Button onClick={() => inputRef.current?.click()} type="button" variant="outline" > <UploadIcon /> Choose files </Button> <input aria-label="Choose files to upload" className="hidden" multiple onChange={(event) => void handleChange(event)} ref={inputRef} type="file" /> </div> <UploadProgress files={files} /> </div> );};export default Example;Installation
npx shadcn@latest add https://files-sdk.dev/r/upload-progress.jsonpnpm dlx shadcn@latest add https://files-sdk.dev/r/upload-progress.jsonbunx --bun shadcn@latest add https://files-sdk.dev/r/upload-progress.jsonUsage
import { useFiles } from "files-sdk/react";
import { UploadProgress } from "@/components/files-sdk/upload-progress";
export function Uploader() {
const files = useFiles({ endpoint: "/api/files" });
return (
<>
<button onClick={() => files.upload(/* … */)} type="button">
Upload
</button>
<UploadProgress files={files} />
</>
);
}Each row shows a file's name, percentage and status (uploading, success, error, aborted). When more than one file is in flight, an aggregate bar is shown on top.
Props
Prop
Type