Input File
newA drag-and-drop file field with previews, built on the native file input.
Drop product shots here
PNG, JPG or WebP · up to 4 images, 5 MB each
Installation
npx shadcn@latest add @blank/input-fileUsage
import {
InputFile,
InputFileDropzone,
InputFileItem,
InputFileList,
InputFileTrigger,
} from "@/components/ui/input-file"<InputFile accept="image/*" multiple value={files} onValueChange={setFiles}>
<InputFileDropzone>
Drop images here
<InputFileTrigger>Browse files</InputFileTrigger>
</InputFileDropzone>
<InputFileList>
{files.map((file) => (
<InputFileItem key={file.name} file={file} />
))}
</InputFileList>
</InputFile>A visually hidden native <input type="file"> does the real work. It keeps the
field in the tab order, opens the system picker on Enter or Space, and holds the
same files you see — so a plain form submit sends them with name, and
required works without JavaScript validation.
Files that break accept, maxSize or maxFiles never reach the value;
onFileReject tells you which rule they broke. Showing that message is
Field's job, not the dropzone's, as the next example does.
InputFileItem renders a preview, the name, the size and a remove button. Pass
children to lay out your own row from the same parts: InputFileItemPreview,
InputFileItemContent, InputFileItemName, InputFileItemSize and
InputFileItemRemove.
Examples
In a field
API Reference
| Prop | Type | Default |
|---|---|---|
value | File[] | — |
defaultValue | File[] | [] |
onValueChange | (files: File[]) => void | — |
accept | string | — |
multiple | boolean | false |
maxSize | number (bytes) | — |
maxFiles | number | — |
onFileReject | (file: File, reason: "type" | "size" | "count") => void | — |
disabled | boolean | false |
name, id, required, aria-invalid, aria-describedby | — | passed to the native input |