velvet-image-dropzone
v1.1.1
Published
A lightweight, developer-friendly React image upload component with drag-and-drop, previews, cropping, multi-upload, and validation — built for React 18 & 19.
Maintainers
Readme
Velvet Dropzone
A modern, lightweight React image upload component. Drag-and-drop, previews, cropping, multi-upload, and validation — with a clean API and a look that fits right into any product.
Built for admin dashboards, CMSs, profile editors, e‑commerce platforms, and SaaS apps. Integrate image uploads in minutes.
npm install velvet-image-dropzoneFeatures
- ✨ Drag & drop upload
- 🖼️ Image preview
- ✂️ Built-in cropping (no extra dependency)
- 📁 Multiple image upload
- 📏 File size validation
- 📄 File type validation
- ⚡ Lightweight — zero runtime dependencies
- 🎨 Customizable UI via CSS variables or a render prop
- 📱 Responsive
- ♿ Accessibility friendly (keyboard operable, ARIA roles)
- 🔒 TypeScript support
- 🎯 React 18 & React 19 compatible
Quick start
import { VelvetDropzone } from "velvet-image-dropzone";
import "velvet-image-dropzone/styles.css";
function AvatarUploader() {
return (
<VelvetDropzone
maxFiles={1}
maxSize={5 * 1024 * 1024}
enableCrop
cropAspects={[{ label: "Square", value: 1 }]}
onFilesChange={(files) => console.log(files)}
/>
);
}Multiple images with validation
<VelvetDropzone
multiple
maxFiles={8}
accept={["image/png", "image/jpeg", "image/webp"]}
maxSize={10 * 1024 * 1024}
label="Drop product photos here"
helperText="PNG, JPG or WEBP — up to 10MB each"
onFilesChange={(files) => setPhotos(files)}
onError={(errors) => errors.forEach((e) => toast.error(e.message))}
/>Full control with a render prop
Use the render prop to build fully custom UI while Velvet Dropzone handles the drag events, validation, and file state.
<VelvetDropzone maxFiles={4} multiple>
{({ isDragActive, files, openFileDialog }) => (
<div className={isDragActive ? "zone zone--active" : "zone"} onClick={openFileDialog}>
{files.length === 0 ? "Click or drop images" : `${files.length} image(s) selected`}
</div>
)}
</VelvetDropzone>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| onFilesChange | (files: VelvetFile[]) => void | — | Fires whenever the accepted file list changes. |
| onError | (errors: VelvetValidationError[]) => void | — | Fires for every rejected file. |
| onCropComplete | (id: string, blob: Blob) => void | — | Fires when a crop is confirmed. |
| accept | string[] | common image types | Accepted MIME types (image/* patterns supported). |
| maxSize | number | 5 * 1024 * 1024 | Max file size in bytes. |
| maxFiles | number | 1 | Max number of files. |
| multiple | boolean | maxFiles > 1 | Allow selecting/dropping more than one file at a time. |
| disabled | boolean | false | Disables all interaction. |
| enableCrop | boolean | false | Shows a crop action on each preview. |
| cropAspects | CropAspect[] | Free / Square / 4:3 / 16:9 | Aspect ratio options in the cropper. Ignored when cropShape is "round". |
| cropShape | "rect" \| "round" | "rect" | "round" forces a 1:1 circular crop — ideal for avatars. |
| autoCropOnSelect | boolean | false | Opens the crop UI immediately after a file is picked/dropped. |
| outputFormat | "image/png" \| "image/jpeg" \| "image/webp" | "image/png" | Encoding used for the cropped output blob. |
| outputQuality | number | 0.92 | Encoding quality (0–1) for lossy formats. |
| showFileList | boolean | true | Shows the row of file thumbnails below the dropzone. |
| label | string | "Drag & drop images here" | Primary copy inside the dropzone. |
| helperText | string | auto-generated | Secondary copy inside the dropzone. |
| className / style | — | — | Passed to the root element. |
| children | render prop | — | Take over rendering entirely. |
Theming
Every color, radius, and spacing token is a CSS variable scoped to .vd-root, so you can restyle the component without overriding specificity:
.vd-root {
--vd-accent: #16a34a;
--vd-radius: 8px;
--vd-border: #d4d4d8;
}TypeScript
Velvet Dropzone is written in TypeScript and ships its own declarations — no @types package needed. Import VelvetFile, VelvetDropzoneProps, VelvetValidationError, and CropAspect directly from velvet-image-dropzone.
Support this project
If Velvet Dropzone saves you time, consider sponsoring the project — it directly funds maintenance and new features. 💜
License
MIT
