DropZone
A drag-and-drop file upload area with file type filtering, size limits, and a file list preview.
Import
import { DropZone } from '@darkcode-ui/react';DropZone is a composable component. You own the file state and render the file list yourself, which keeps the upload flow fully under your control.
Usage
import {DropZone} from "@darkcode-ui/react";
export function Default() {
return (
<DropZone className="w-full max-w-md">Anatomy
Import the DropZone component and access all parts using dot notation.
import { DropZone } from '@darkcode-ui/react';
<DropZone>
<DropZone.Area>
<DropZone.Icon />
<DropZone.Label>Drag files here or click to browse</DropZone.Label>
<DropZone.Description>PDF, DOCX, PNG, or JPG up to 10 MB.</DropZone.Description>
<DropZone.Trigger>Select files</DropZone.Trigger>
</DropZone.Area>
<DropZone.Input />
<DropZone.FileList>
<DropZone.FileItem status="uploading">
<DropZone.FileFormatIcon format="PDF" color="red" />
<DropZone.FileInfo>
<DropZone.FileName>Proposal.pdf</DropZone.FileName>
<DropZone.FileMeta>2.4 MB</DropZone.FileMeta>
</DropZone.FileInfo>
<DropZone.FileProgress value={68}>
<DropZone.FileProgressTrack>
<DropZone.FileProgressFill />
</DropZone.FileProgressTrack>
</DropZone.FileProgress>
<DropZone.FileRetryTrigger />
<DropZone.FileRemoveTrigger />
</DropZone.FileItem>
</DropZone.FileList>
</DropZone>;With File List
Render DropZone.FileList with one DropZone.FileItem per file. The list animates items in and out as your state changes.
import {DropZone} from "@darkcode-ui/react";
export function WithFileList() {
return (
<DropZone className="w-full max-w-md">Compact File List
Pass compact to DropZone.FileList for a denser layout, useful when many files are listed.
import {DropZone} from "@darkcode-ui/react";
export function CompactFileList() {
return (
<DropZone className="w-full max-w-md">Disabled
Set isDisabled on DropZone.Area to prevent dropping. The Trigger inside the area is disabled automatically.
import {DropZone} from "@darkcode-ui/react";
export function Disabled() {
return (
<DropZone className="w-full max-w-md">Image Only
Use the accept prop on DropZone.Input to restrict the file picker to specific file types.
import {DropZone} from "@darkcode-ui/react";
export function ImageOnly() {
return (
<DropZone className="w-full max-w-md">Max Size Limit
Validate file size in your onSelect handler and mark oversized files with status="failed", then offer a retry.
"use client";
import {DropZone} from "@darkcode-ui/react";
import React from "react";
Multiple Files
Pass multiple to DropZone.Input and collect files from both the picker (onSelect) and drag-and-drop (onDrop).
"use client";
import {DropZone} from "@darkcode-ui/react";
import React from "react";
Custom Icon
Provide children to DropZone.Icon to replace the default cloud upload icon.
import {DropZone} from "@darkcode-ui/react";
export function CustomIcon() {
return (
<DropZone className="w-full max-w-md">Custom Triggers
The Trigger, retry, and remove buttons all accept className and custom children for full control over their appearance.
import {DropZone} from "@darkcode-ui/react";
export function CustomTriggers() {
return (
<DropZone className="w-full max-w-md">useDropZone Hook
The useDropZone hook manages the whole upload lifecycle — file state, validation, image previews, and uploads — so you only render the UI. Spread getAreaProps() onto DropZone.Area and getInputProps() onto DropZone.Input, then map files to DropZone.FileItem. Rejections (wrong type, too large, too many) are reported via onFilesRejected.
"use client";
import {DropZone, formatFileSize, useDropZone} from "@darkcode-ui/react";
import React from "react";
Image Previews
DropZone.FilePreview renders an image thumbnail from a File or a URL string, with automatic object-URL cleanup and a graceful fallback (a file format icon) for non-images or load errors. useDropZone populates file.preview for images automatically.
"use client";
import {DropZone, formatFileSize, useDropZone} from "@darkcode-ui/react";
export function ImagePreview() {Upload Progress
Pass onUpload (or uploadUrl) to useDropZone to upload each accepted file with live progress. Failed uploads surface a retry, and removing a file aborts its upload. For real uploads, use the exported uploadFile helper — it is XMLHttpRequest-based, so it reports true progress and supports AbortSignal.
"use client";
import type {DropZoneFile, UseDropZoneUploadHelpers} from "@darkcode-ui/react";
import {DropZone, formatFileSize, useDropZone} from "@darkcode-ui/react";Directory & Paste
Set acceptDirectory on DropZone.Input to select an entire folder (webkitdirectory), or capture for the mobile camera. Clipboard paste (⌘/Ctrl + V) is supported automatically when the area is focused — pasted files flow through the same onDrop handler.
"use client";
import {DropZone, formatFileSize, useDropZone} from "@darkcode-ui/react";
function badge(name: string): {color: string; format: string} {Styling
Customizing the component classes
To customize the DropZone component classes, you can use the @layer components directive.
Learn more.
@layer components {
.drop-zone__area {
@apply rounded-xl border-foreground/20;
}
.drop-zone__file-item {
@apply bg-default/40;
}
}DarkCode UI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.
CSS Classes
The DropZone component uses these CSS classes (View source styles):
Base Classes
.drop-zone- Root wrapper
Element Classes
.drop-zone__area- The droppable area (RAC DropZone).drop-zone__icon- Upload icon container.drop-zone__label- Primary label text.drop-zone__description- Secondary description text.drop-zone__trigger- Browse button.drop-zone__input- Hidden file input.drop-zone__file-list- File list container with animation.drop-zone__file-item- Individual file entry.drop-zone__file-format-icon- File type SVG icon with colored badge.drop-zone__file-info- File name and metadata container.drop-zone__file-name- File name text.drop-zone__file-meta- File size/status metadata.drop-zone__file-progress- Upload progress bar.drop-zone__file-retry-trigger- Retry button for failed uploads.drop-zone__file-remove-trigger- Remove/close button
Modifier Classes
.drop-zone__file-list--compact- Denser file list layout.drop-zone__file-format-icon--{color}- Badge color (gray,red,orange,amber,green,blue,purple)
Interactive States
- Drop target:
[data-drop-target="true"]on.drop-zone__area(accent border and background) - Focus visible:
[data-focus-visible="true"]on.drop-zone__area(focus ring) - Disabled:
[data-disabled="true"]on.drop-zone__area(reduced opacity) - File status:
[data-status="uploading|complete|failed"]on.drop-zone__file-item
API Reference
DropZone
The root wrapper component. Provides file picker context.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Area, FileList, and other sub-components |
className | string | - | Additional CSS class |
render | DOMRenderFunction | - | Custom render function to override the default div element |
Also supports all native div HTML attributes.
DropZone.Area
The droppable area. Wraps RAC DropZone.
Also supports all RAC DropZone props (onDrop, getDropOperation, isDisabled, etc.).
DropZone.Icon
Upload icon container. Renders a default cloud upload icon when no children are provided.
DropZone.Label
Primary label text. Wraps RAC Text with slot="label".
DropZone.Description
Secondary description text.
DropZone.Input
Hidden file input for the browse trigger.
| Prop | Type | Default | Description |
|---|---|---|---|
accept | string | - | Accepted file types (e.g. "image/*,.pdf") |
multiple | boolean | - | Whether multiple files can be selected |
acceptDirectory | boolean | - | Allow selecting an entire directory (sets webkitdirectory) |
capture | boolean | "user" | "environment" | - | Mobile capture mode for the camera/microphone |
onSelect | (files: FileList) => void | - | Called when files are selected via the file picker |
DropZone.Trigger
Browse button that opens the file picker. Wraps RAC Button. When no children are provided, it renders Select files.
DropZone.FileList
Animated file list container using Motion AnimatePresence.
| Prop | Type | Default | Description |
|---|---|---|---|
compact | boolean | false | Renders a denser layout for the file rows |
DropZone.FileItem
Individual file entry with Motion layout animations.
| Prop | Type | Default | Description |
|---|---|---|---|
status | 'uploading' | 'complete' | 'failed' | - | Upload status of this file item |
DropZone.FileFormatIcon
File type SVG icon with a colored format badge.
| Prop | Type | Default | Description |
|---|---|---|---|
format | string | - | File format label (e.g. "PDF", "JPG") |
color | string | 'gray' | Badge color (gray, red, orange, amber, green, blue, purple) |
DropZone.FilePreview
Image thumbnail for a file. Renders an <img> from a File (creating and revoking an object URL automatically) or a URL string, and falls back to a file format icon for non-images or load errors.
| Prop | Type | Default | Description |
|---|---|---|---|
src | File | string | - | A File (object URL is managed for you) or an image URL |
fallback | ReactNode | <DropZone.FileFormatIcon /> | Rendered when there is no preview or the image fails to load |
Also supports all native img HTML attributes.
DropZone.FileInfo
Container for file name and metadata.
DropZone.FileName
File name text display.
DropZone.FileMeta
File size/status metadata text.
DropZone.FileProgress
Upload progress bar. Wraps DarkCode UI ProgressBar.
| Prop | Type | Default | Description |
|---|---|---|---|
size | string | 'sm' | Progress bar size |
Also supports all ProgressBar props.
DropZone.FileProgressTrack
Progress bar track. Wraps ProgressBar.Track.
DropZone.FileProgressFill
Progress bar fill. Wraps ProgressBar.Fill.
DropZone.FileRetryTrigger
Retry button for failed uploads. Wraps RAC Button.
DropZone.FileRemoveTrigger
Remove/close button. Wraps RAC Button.
Hooks & helpers
useDropZone
A headless hook that manages file state, validation, image previews, and uploads. Returns the file list and prop getters to wire onto the presentational parts.
import { useDropZone } from '@darkcode-ui/react';
const dz = useDropZone({
accept: 'image/*,.pdf',
maxSize: 5 * 1024 * 1024,
maxFiles: 5,
onUpload: (file, { onProgress, signal }) => upload(file, onProgress, signal),
});
// <DropZone.Area {...dz.getAreaProps()}>
// <DropZone.Input {...dz.getInputProps()} />
// dz.files.map(...) → dz.removeFile(id), dz.retryFile(id)Options
| Option | Type | Default | Description |
|---|---|---|---|
files | DropZoneFile[] | - | Controlled file state |
defaultFiles | DropZoneFile[] | [] | Initial (uncontrolled) file state |
onFilesChange | (files: DropZoneFile[]) => void | - | Called whenever the file list changes |
accept | string | - | Accepted file types (same syntax as the input accept) |
maxSize | number | - | Maximum size per file, in bytes |
minSize | number | - | Minimum size per file, in bytes |
maxFiles | number | - | Maximum number of files allowed in total |
multiple | boolean | maxFiles !== 1 | Whether multiple files can be selected |
validate | (file: File) => string | null | - | Custom validator; return a message to reject |
disabled | boolean | false | Disable selection, drop, and validation |
generatePreviews | boolean | true | Create object-URL previews for image files |
onFilesAccepted | (files: DropZoneFile[]) => void | - | Called with the files that were added |
onFilesRejected | (rejections: DropZoneRejection[]) => void | - | Called with the files that failed validation |
onUpload | (file, helpers) => Promise | - | Upload implementation per file (helpers: onProgress, signal) |
uploadUrl | string | - | Convenience endpoint; uploads via uploadFile when onUpload is not set |
uploadOptions | UploadFileOptions | - | Extra options forwarded to uploadFile when uploadUrl is used |
Returns
| Property | Type | Description |
|---|---|---|
files | DropZoneFile[] | Current files |
isDisabled | boolean | Whether the drop zone is disabled |
totalSize | number | Combined byte size of all files |
addFiles | (files: FileList | File[]) => void | Validate and add files |
removeFile | (id: string) => void | Remove a file (aborts upload, revokes preview) |
retryFile | (id: string) => void | Retry a failed/aborted upload |
updateFile | (id: string, patch: Partial<DropZoneFile>) => void | Patch a single file entry |
clear | () => void | Remove all files |
getInputProps | () => object | Props to spread onto DropZone.Input |
getAreaProps | () => object | Props to spread onto DropZone.Area (also enables paste) |
DropZoneFile is { id, file, name, size, type, status, progress, error?, preview? }, where status is 'pending' | 'uploading' | 'complete' | 'failed'.
uploadFile
XMLHttpRequest-based upload helper with real progress events and abort support. Pass it to useDropZone's onUpload, or call it directly.
import { uploadFile } from '@darkcode-ui/react';
await uploadFile(file, {
url: '/api/upload',
onProgress: ({ percent }) => setProgress(percent ?? 0),
signal: controller.signal,
});| Option | Type | Default | Description |
|---|---|---|---|
url | string | - | Endpoint the file is uploaded to |
method | string | "POST" | HTTP method |
fieldName | string | "file" | Form field name for the file part |
headers | Record<string, string> | - | Additional request headers |
data | Record<string, string | Blob> | - | Extra fields appended to the FormData |
withCredentials | boolean | false | Send cookies/credentials cross-origin |
signal | AbortSignal | - | Cancels the in-flight upload |
onProgress | (progress) => void | - | Progress callback ({ loaded, total, percent }) |
formatFileSize
formatFileSize(bytes, decimals?) formats a byte count into a human-readable string (e.g. 2.4 MB).





