Click to upload or drag and drop
PNG, JPG or PDF (max. 10MB)
<FileUpload class="w-full max-w-md space-y-4">
<FileUploadInput name="files" multiple />
<FileUploadDropzone>
<HugeIcon icon={Upload01Icon} class="size-6 text-muted-foreground" />
<div class="text-sm text-muted-foreground">
<span class="font-medium text-foreground">Click to upload</span> or drag and drop
</div>
<p class="text-xs text-muted-foreground">PNG, JPG or PDF (max. 10MB)</p>
</FileUploadDropzone>
<FileUploadPreview />
</FileUpload>Installation
npx bearnie add file-uploadbunx bearnie add file-uploadpnpm dlx bearnie add file-uploadyarn dlx bearnie add file-uploadUsage
import {
FileUpload,
FileUploadTrigger,
FileUploadInput,
FileUploadDropzone,
FileUploadPreview,
} from "@/components/bearnie/file-upload"<FileUpload class="space-y-4">
<FileUploadInput name="file" />
<FileUploadDropzone />
<FileUploadPreview />
</FileUpload>Examples
With button trigger
<FileUpload class="inline-flex flex-col items-start gap-3">
<FileUploadInput name="avatar" accept="image/*" />
<FileUploadTrigger>
<HugeIcon icon={Upload01Icon} class="mr-2 size-4" />
Upload Avatar
</FileUploadTrigger>
<FileUploadPreview class="mt-0" />
</FileUpload>Single file
Upload a document
PDF, DOC, or DOCX
<FileUpload class="w-full max-w-md space-y-4">
<FileUploadInput name="document" accept=".pdf,.doc,.docx" />
<FileUploadDropzone>
<HugeIcon icon={Upload01Icon} class="size-5 text-muted-foreground" />
<p class="text-sm text-muted-foreground">Upload a document</p>
<p class="text-xs text-muted-foreground">PDF, DOC, or DOCX</p>
</FileUploadDropzone>
<FileUploadPreview />
</FileUpload>Multiple files
Upload multiple images
Select multiple files or drag them here
<FileUpload class="w-full max-w-md space-y-4">
<FileUploadInput name="photos" multiple accept="image/*" />
<FileUploadDropzone>
<HugeIcon icon={Upload01Icon} class="size-5 text-muted-foreground" />
<p class="text-sm text-muted-foreground">Upload multiple images</p>
<p class="text-xs text-muted-foreground">Select multiple files or drag them here</p>
</FileUploadDropzone>
<FileUploadPreview />
</FileUpload>Props
FileUpload
Root container that manages the file upload state.
| Prop | Type | Default | Description |
|---|---|---|---|
| multiple | boolean | false | Allow multiple file selection |
| accept | string | - | Accepted file types (extensions, MIME types, or wildcards like image/*). Enforced on both picker selection and drag-and-drop |
| maxSize | number | - | Maximum file size in bytes. Files over the limit are rejected with a visible error |
| disabled | boolean | false | Disable the upload |
| class | string | - | Additional CSS classes |
Rejected files are removed from the input and listed in an error message below the upload (rendered into a [data-file-upload-error] element, created automatically if you don’t provide one). If accept is only set on FileUploadInput, it’s used for drag-and-drop validation too.
FileUploadInput
Hidden file input element.
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | - | Input name for form submission |
| multiple | boolean | false | Allow multiple files |
| accept | string | - | Accepted file types |
FileUploadDropzone
Visual drop area for drag and drop. Clicking also opens the file picker.
FileUploadTrigger
Optional button to trigger file selection without the dropzone.
FileUploadPreview
Displays selected files with name, size, and remove button.
Events
The root element dispatches a bubbling file-upload-change CustomEvent whenever the selection changes (picker, drop, or remove):
document.querySelector("[data-file-upload]").addEventListener("file-upload-change", (e) => {
const { files, rejected } = e.detail;
// files: File[] currently selected
// rejected: { file: File, reason: "accept" | "maxSize" }[]
});