File Upload
A component for uploading files
Default
Default file upload
Upload your files
Drag and drop or click to browse
Files up to 5.0 MB · Maximum 5 files
default-example.tsx
1"use client";23import { FileUpload } from "@/registry/ui";45export function FileUploadDefaultExample() {6 return (7 <div className="mx-auto w-full max-w-2xl">8 <FileUpload9 maxFiles={5}10 maxConcurrentUploads={2}11 onUpload={async (_, onProgress, signal) => {12 return new Promise<void>((resolve, reject) => {13 let progress = 0;1415 const interval = window.setInterval(() => {16 if (signal.aborted) {17 window.clearInterval(interval);18 reject(new DOMException("Upload cancelled", "AbortError"));19 return;20 }2122 progress = Math.min(progress + 10, 100);23 onProgress(progress);2425 if (progress === 100) {26 window.clearInterval(interval);27 resolve();28 }29 }, 200);30 });31 }}32 />33 </div>34 );35}
Edge Cases
File upload with edge cases
In-progress upload
Demo only - uploads stall at 88% and never complete.
Upload your files
Drag and drop or click to browse
Files up to 5.0 MB · Maximum 3 files
Error and retry
The first attempt fails at 60%. Press retry to complete it.
Upload your files
Drag and drop or click to browse
Files up to 5.0 MB · Maximum 3 files
edge-cases.tsx
1"use client";23import { useRef } from "react";45import {6 Card,7 CardContent,8 CardDescription,9 CardHeader,10 CardTitle,11} from "@/components/ui/card";12import { FileUpload } from "@/registry/ui";1314type UploadHandler = (15 file: File,16 onProgress: (progress: number) => void,17 signal: AbortSignal,18) => Promise<void>;1920function simulateUpload({21 onProgress,22 signal,23 shouldFail = false,24}: {25 onProgress: (progress: number) => void;26 signal: AbortSignal;27 shouldFail?: boolean;28}) {29 return new Promise<void>((resolve, reject) => {30 let progress = 0;3132 const interval = window.setInterval(() => {33 if (signal.aborted) {34 window.clearInterval(interval);35 reject(new DOMException("Upload cancelled", "AbortError"));36 return;37 }3839 progress = Math.min(progress + 10, 100);40 onProgress(progress);4142 if (shouldFail && progress >= 60) {43 window.clearInterval(interval);44 reject(new Error("Simulated upload failure"));45 return;46 }4748 if (progress === 100) {49 window.clearInterval(interval);50 resolve();51 }52 }, 180);53 });54}5556export function FileUploadEdgeCasesExample() {57 const attemptsRef = useRef(new Map<string, number>());5859 const handleIndefiniteUpload: UploadHandler = async (60 _,61 onProgress,62 signal,63 ) => {64 // Demo-only: stalls below completion so the uploading UI stays visible.65 let progress = 0;66 onProgress(progress);6768 await new Promise<void>((_, reject) => {69 const interval = window.setInterval(() => {70 if (signal.aborted) {71 window.clearInterval(interval);72 reject(new DOMException("Upload cancelled", "AbortError"));73 return;74 }7576 progress = Math.min(progress + 4, 88);77 onProgress(progress);78 }, 200);79 });80 };8182 const handleRetryUpload: UploadHandler = async (file, onProgress, signal) => {83 const fileKey = `${file.name}-${file.size}-${file.lastModified}`;84 const attempts = attemptsRef.current.get(fileKey) ?? 0;8586 attemptsRef.current.set(fileKey, attempts + 1);8788 await simulateUpload({89 onProgress,90 signal,91 shouldFail: attempts === 0,92 });93 };9495 return (96 <div className="grid gap-6 lg:grid-cols-2">97 <Card>98 <CardHeader>99 <CardTitle className="text-base">In-progress upload</CardTitle>100 <CardDescription>101 Demo only - uploads stall at 88% and never complete.102 </CardDescription>103 </CardHeader>104105 <CardContent>106 <FileUpload107 maxFiles={3}108 maxConcurrentUploads={2}109 onUpload={handleIndefiniteUpload}110 />111 </CardContent>112 </Card>113114 <Card>115 <CardHeader>116 <CardTitle className="text-base">Error and retry</CardTitle>117 <CardDescription>118 The first attempt fails at 60%. Press retry to complete it.119 </CardDescription>120 </CardHeader>121122 <CardContent>123 <FileUpload124 maxFiles={3}125 maxConcurrentUploads={1}126 onUpload={handleRetryUpload}127 />128 </CardContent>129 </Card>130 </div>131 );132}
Installation & source
Install via the shadcn CLI or copy the registry files manually.
bash
npx shadcn@latest add @tt-ui/file-upload
Props
| Name | Type | Default | Description |
|---|---|---|---|
| onUpload | () => void | undefined | Callback when a file is uploaded |
| accept | string | image/*,application/pdf | The accept attribute for the file input |
| maxSize | number | 5_000_000 | The maximum size of the file in bytes |
| maxFiles | number | undefined | The maximum number of files to upload |
| maxConcurrentUploads | number | undefined | The maximum number of concurrent uploads |
| className | string | undefined | The class name of the file upload |