- Components
- Form
- File Upload
Shadcn File Upload Components
An upload area that accepts files through drag and drop or the file browser. Every file upload variant works with both Radix UI and Base UI setups. Browse our collection of 10 Shadcn File Upload variants.
Dropzone
Drop your image here or click to browse
Max size: 5MB
With button
Drop your image here
SVG, PNG, JPG or GIF (max. 5MB)
Multiple files
Files (3)
brand-assets.zip
246.95KB
cover-photo.jpg
1.46MB
intro-theme.mp3
1.46MB
With preview

team-workspace.jpg
Thumbnail

analytics-overview.jpeg
Profile form
Pick a photo up to 1MB.
Review form
Chat attachment

dashboard-preview.jpeg
259.3KB
Profile card

108 characters left
Chat attachments
Unlock premium components
Explore Shadcn Blocks
Ready-made page sections built with the same components.
Shadcn File Upload Component
The Shadcn File Upload is an upload area that accepts files through drag and drop or the system file browser, validates them and shows what was picked before anything is sent to a server. Avatars, product photos, documents and chat attachments all start here, and a clear upload experience removes one of the most common points of friction in a form.
Image dropzones, multi file lists with names and sizes, compact thumbnail pickers and chat composers with attachments make up this React file upload component collection, with profile and review form layouts available as Pro. The logic lives in a small useFileUpload hook on top of the native file input, with no extra upload library, while the buttons, inputs and cards around it are regular shadcn/ui components styled with Tailwind CSS in React. That is why every variant works in both Radix UI and Base UI setups.
What is the Shadcn File Upload Component?
A file upload component combines a hidden <input type="file"> with a visible drop zone or button. When files arrive, the hook checks them against the allowed types, the maximum size and the maximum count, creates preview URLs for images and returns the list together with any error messages. Your UI only has to render that state: a thumbnail, a file list, an error line or a remove button.
Use it whenever users need to attach real files. For a single plain field inside a larger form, a native file Input can be enough, and for showing files that are already attached to a message or record, the Attachment component is a better fit. If you need to show upload progress after the files are sent, pair the list with a Progress bar.
Anatomy of the Shadcn File Upload
| Part | Description |
|---|---|
| useFileUpload | The hook from hooks/use-file-upload. Takes accept, maxSize, multiple, maxFiles, initialFiles and change callbacks, and returns a state object and an actions object. |
| files / errors / isDragging | The state. Each file has an id, the original file and a preview URL; errors are ready to display strings; isDragging is true while files hover over the drop zone. |
| getInputProps | Returns the props for the hidden file input: type, accept, multiple, change handler and ref. |
| Drag handlers | handleDragEnter, handleDragLeave, handleDragOver and handleDrop, spread onto any element to turn it into a drop zone. |
| openFileDialog / addFiles | Open the system file browser from any button, or add files programmatically, for example from a paste event. |
| removeFile / clearFiles / clearErrors | Remove one file by id, remove all files, or reset the error messages. Image preview URLs are revoked when files are removed or cleared. |
| formatBytes | A helper exported from the same hook file that turns a byte count into readable text such as 2.4MB for file lists. |
10 Shadcn File Upload Variants
Each file upload variant listed here is previewed live at the top of this page, together with its source code and install command.
- Dropzone: A dashed image drop area that switches to a preview with a remove button once a file is added.
- With button: A drop zone with an explicit Select image button and a hint listing SVG, PNG, JPG or GIF up to 5MB.
- Multiple files: Up to six files of any type with a file list showing names and sizes, plus Add files and Remove all actions.
- With preview and thumbnail: Two compact single image pickers: an Upload image button with a small thumbnail, the file name and a Remove link, or a square dashed thumbnail slot with a round remove button.
- Chat attachments: Free message composers: one with a paperclip button that shows a single attached file with its size, and one where up to six images can be picked or dropped onto the composer and appear as a row of thumbnails above the input.
- Profile forms: Pro layouts in a card: a Profile form with a round avatar upload above name and email fields, and a Profile card with a cover image and avatar upload plus first name, last name, username, website and biography fields.
- Review form: A Pro product review card with title and description fields, a drop zone for up to six photos, a yes or no recommendation radio group and a terms checkbox.
How to Install the Shadcn File Upload Component
Set up shadcn/ui in your project if you have not already, then add the Shadcn UI Kit registry to your components.json once:
{
"registries": {
"@shadcnuikit": "https://shadcnuikit.com/r/{name}.json"
}
}Then install a file upload variant by its name:
npx shadcn@latest add @shadcnuikit/file-upload1The same command works with pnpm dlx, yarn dlx and bunx --bun. Each variant has a copy button for every package manager, and the code is added to your project as plain React and Tailwind CSS that you can edit freely.
How to Use the Shadcn File Upload Component
Call useFileUpload with your limits, spread getInputProps() onto a visually hidden input and connect the drag handlers and openFileDialog to your drop zone.
"use client"
import { UploadIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { useFileUpload } from "@/hooks/use-file-upload"
export function DocumentUpload() {
const [
{ files, isDragging, errors },
{
handleDragEnter,
handleDragLeave,
handleDragOver,
handleDrop,
openFileDialog,
removeFile,
getInputProps,
},
] = useFileUpload({ accept: ".pdf", maxSize: 10 * 1024 * 1024 })
return (
<div
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
onDrop={handleDrop}
data-dragging={isDragging || undefined}
className="flex flex-col items-center gap-3 rounded-xl border border-dashed p-6 data-[dragging=true]:bg-accent/40"
>
<input {...getInputProps()} className="sr-only" aria-label="Upload PDF" />
<Button variant="outline" onClick={openFileDialog}>
<UploadIcon aria-hidden="true" />
Select PDF
</Button>
{files[0] && (
<Button variant="link" onClick={() => removeFile(files[0].id)}>
Remove {files[0].file.name}
</Button>
)}
{errors[0] && (
<p role="alert" className="text-sm text-destructive">
{errors[0]}
</p>
)}
</div>
)
}Why Use the Shadcn File Upload Component
- No upload library needed: Validation, previews and drag state come from one small hook built on the native file input.
- Validation before upload: File type, size and count are checked on the client, so users see errors instantly.
- Instant previews: Images get object URLs for thumbnails, and those URLs are cleaned up when files are removed.
- Any layout you want: The hook has no markup, so the same logic powers drop zones, avatar pickers and chat composers.
- Backend agnostic: You get real File objects and decide how to send them: FormData, presigned URLs or a server action.
Common File Upload Use Cases
- Profile pictures: Round avatar pickers with an instant preview in account settings.
- Product media: Multiple product or listing photos in e-commerce and marketplace admin panels.
- Document submission: Invoices, contracts and ID documents in onboarding and support forms.
- Chat and comments: Attach images and files to messages before sending.
- Reviews: Let customers add photos to a product review.
- Data import: Accept CSV or spreadsheet files for bulk import screens.
Customizing the Shadcn File Upload
Since the hook returns only state and handlers, every visual detail is yours. Style the drag over state with data-[dragging=true]: classes, change the drop zone shape from a wide rectangle to a round avatar, and restrict files with accept values like image/* or .pdf,.docx. Use onFilesAdded to start an upload as soon as files are picked, or initialFiles to show files that already exist on the server. Colors follow your theme tokens, which you can generate with the free Theme Generator.
import { useFileUpload, type FileWithPreview } from "@/hooks/use-file-upload"
async function uploadToServer(items: FileWithPreview[]) {
const body = new FormData()
for (const { file } of items) {
if (file instanceof File) body.append("files", file)
}
await fetch("/api/upload", { method: "POST", body })
}
const [{ files, errors }, actions] = useFileUpload({
accept: "image/*",
multiple: true,
maxFiles: 6,
maxSize: 5 * 1024 * 1024,
onFilesAdded: (added) => void uploadToServer(added),
})File Upload Accessibility and Keyboard Support
Drag and drop is not available to keyboard or screen reader users, so every variant also opens the file browser from a focusable button. When the whole drop zone is clickable, give it role="button", tabIndex={0}, an aria-label such as "Upload image" and handle Enter and Space, as the dropzone variant does.
Keep the hidden input in the DOM with sr-only and its own label, give remove buttons labels like "Remove image", and render validation errors with role="alert", as the dropzone, multiple files and chat variants do, so they are announced right away. Image previews should use the file name as alt text.
| Key | Action |
|---|---|
| Tab | Moves focus to the drop zone, upload button or remove button. |
| ShiftTab | Moves focus to the previous focusable element. |
| Enter | Opens the file browser from the focused drop zone or button. |
| Space | Opens the file browser from the focused drop zone or button. |
File Upload Best Practices
- Tell users the allowed file types and maximum size before they pick a file.
- Always offer a button in addition to drag and drop, especially on mobile where dragging is rare.
- Show a preview or at least the file name and size so users can confirm the right file.
- Validate again on the server; client side checks improve UX but can be bypassed.
- Make removing a file one click, and disable the add button when the file limit is reached.
- Show progress for large uploads with a Progress bar next to each file.
Components Related to File Upload
Shadcn File Upload FAQ
Looking for something else? Browse all shadcn/ui components or ready-made UI blocks built with them.



















