@input-kit/dropzone
v0.1.0
Published
File dropzone
Downloads
82
Maintainers
Readme
@input-kit/dropzone
Headless file dropzone hook and component for React. Fully typed, keyboard accessible, with image preview support and automatic cleanup of object URLs.
Comparison with react-dropzone
| Feature | @input-kit/dropzone | react-dropzone |
|---|---|---|
| Bundle size | ~4 KB | ~20 KB |
| Dependencies | zero | file-selector |
| TypeScript | full | full |
| Keyboard (Space/Enter) | yes | yes |
| Image previews | built-in | manual (onDrop) |
| File type accept format | string/string[] | MIME object { 'image/*': ['.png'] } |
| Object URL cleanup | auto on unmount | manual |
| SSR | safe | safe |
Installation
npm install @input-kit/dropzoneQuick Start
import { useDropzone } from '@input-kit/dropzone';
function MyDropzone() {
const { getRootProps, getInputProps, files, removeFile } = useDropzone({
accept: 'image/*',
maxFiles: 5,
maxSize: 5 * 1024 * 1024, // 5 MB
});
return (
<div {...getRootProps()} style={{ border: '2px dashed #ccc', padding: 32 }}>
<input {...getInputProps()} />
<p>Drag files here or press Space / Enter to browse</p>
{files.map(f => (
<div key={f.id}>
{f.preview && <img src={f.preview} width={80} alt={f.name} />}
<span>{f.name}</span>
<button onClick={() => removeFile(f.id)}>Remove</button>
</div>
))}
</div>
);
}Drop-in Dropzone component
import { Dropzone } from '@input-kit/dropzone';
<Dropzone
accept="image/*,.pdf"
maxSize={10 * 1024 * 1024}
maxFiles={3}
onDrop={(files) => console.log(files)}
onRemove={(file) => console.log('removed', file.name)}
/>API
useDropzone(options?)
const {
files, // FileWithPreview[] — accepted files
isDragActive, // boolean — drag is over the zone
isDragAccept, // boolean — all dragged files appear valid
isDragReject, // boolean — some dragged files appear invalid
getRootProps, // () => root element props (drag, click, keyboard)
getInputProps, // () => hidden <input> props
open, // () => void — programmatically open file dialog
removeFile, // (id: string) => void — remove a file and revoke its preview URL
clearFiles, // () => void — remove all files
} = useDropzone(options);UseDropzoneOptions
| Option | Type | Default | Description |
|---|---|---|---|
| accept | string \| string[] | — | Accepted MIME types or extensions. e.g. 'image/*', ['.pdf', '.docx'] |
| maxSize | number | Infinity | Maximum file size in bytes |
| maxFiles | number | Infinity | Maximum number of accepted files |
| multiple | boolean | true | Allow multiple files |
| disabled | boolean | false | Disable all interaction |
| onDrop | (accepted, rejected) => void | — | Called after every drop |
| onDropAccepted | (files) => void | — | Called when at least one file is accepted |
| onDropRejected | (rejections) => void | — | Called when at least one file is rejected |
| validator | (file) => FileRejection \| null | — | Custom per-file validator |
FileWithPreview
Extends File with two additional fields:
| Field | Type | Description |
|---|---|---|
| id | string | Unique ID for use as React key |
| preview | string \| undefined | Object URL for image files (revoked automatically on removal/unmount) |
FileRejection
interface FileRejection {
file: File;
errors: FileError[];
}
interface FileError {
code: 'file-too-large' | 'file-invalid-type' | 'too-many-files' | 'custom';
message: string;
}DropzoneProps
| Prop | Type | Default | Description |
|---|---|---|---|
| accept | string \| string[] | — | Accepted types/extensions |
| maxSize | number | — | Max file size in bytes |
| maxFiles | number | — | Max accepted file count |
| multiple | boolean | true | Allow multiple files |
| disabled | boolean | false | Disable interaction |
| onDrop | (files: File[]) => void | — | Called with accepted files |
| onRemove | (file: FileWithPreview) => void | — | Called when a file is removed |
| showPreview | boolean | true | Show built-in file list preview |
| className | string | — | Class for the outer wrapper |
| style | CSSProperties | — | Style for the outer wrapper |
| children | ReactNode \| ((state: { isDragActive }) => ReactNode) | — | Custom render content |
Keyboard Accessibility
The root element receives tabIndex={0}, role="button", and an aria-label. Space and Enter open the file dialog, matching the behaviour of react-dropzone.
File Type Validation
Accepts the same accept string as the HTML <input type="file"> attribute:
useDropzone({ accept: 'image/png,image/jpeg' })
useDropzone({ accept: ['.pdf', '.docx', 'image/*'] })Note: Browsers do not expose MIME types during drag events for security reasons.
isDragAcceptandisDragRejectare best-effort during drag and are reliable only after the drop.
Notes vs react-dropzone
react-dropzone'sacceptformat is{ 'image/*': ['.png'] }(MIME object)@input-kit/dropzoneuses the simpler HTMLacceptstring format consistently- Image preview URLs are generated automatically and revoked on
removeFile,clearFiles, or component unmount — no manual cleanup needed react-dropzonehasnoClick,noDrag,noKeyboardescape hatches; this package does not currently expose them
TypeScript
import type { FileWithPreview, FileRejection, FileError, UseDropzoneOptions, DropzoneProps } from '@input-kit/dropzone';License
MIT © Harshit
