Image Dropzone
Drag & drop or click to select an image, with preview support.
Image Dropzone Demo
Drag & drop or click to select an image. Shows a preview.
Installation
Copy and paste the following code into your project.
import { cn } from '@kit/shared';
import { Button } from '@kit/ui/button';
import { Icon } from '@kit/ui/icon';
import React, { useCallback, useMemo } from 'react';
import { useDropzone, type DropEvent, type DropzoneOptions, type FileRejection } from 'react-dropzone';
export interface ImageDropzoneProps {
title?: string;
subtitle?: string;
src?: string;
borderRadius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
className?: string;
onDrop?: (acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent) => void;
onError?: (error: Error) => void;
children?: React.ReactNode;
}
export const ImageDropzone: React.FC<ImageDropzoneProps & Omit<DropzoneOptions, 'onDrop' | 'onError'>> = ({
accept,
maxFiles = 1,
maxSize,
minSize,
onDrop,
onError,
disabled,
title = 'Upload image',
subtitle = 'Drag & drop or click to select',
src,
borderRadius = 'none',
className,
children,
...dropzoneProps
}) => {
const dropzoneOptions: DropzoneOptions = useMemo(
() => ({
accept,
maxFiles,
maxSize,
minSize,
onDrop: (acceptedFiles, fileRejections, event) => {
if (fileRejections.length > 0) {
onError?.(new Error(`File rejected: ${fileRejections[0]?.errors[0]?.message ?? ''}`));
} else {
onDrop?.(acceptedFiles, fileRejections, event);
}
},
disabled,
...dropzoneProps,
}),
[accept, maxFiles, maxSize, minSize, onDrop, onError, disabled, dropzoneProps]
);
const { getRootProps, getInputProps, isDragActive } = useDropzone(dropzoneOptions);
const borderRadiusClass = useMemo(() => ({
none: '',
sm: 'rounded-xs',
md: 'rounded-md',
lg: 'rounded-lg',
xl: 'rounded-xl',
'2xl': 'rounded-2xl',
'3xl': 'rounded-3xl',
full: 'rounded-full',
}[borderRadius]), [borderRadius]);
const renderContent = useCallback(() => {
if (!src) {
return (
children || (
<>
<div className="bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-full">
<Icon.upload className="size-5 shrink-0" />
</div>
<p className="mt-2 text-sm font-medium">{title}</p>
<p className="text-muted-foreground text-xs">{subtitle}</p>
</>
)
);
}
return (
<img
src={src}
alt={title}
className={cn('size-full max-h-full max-w-full object-cover', borderRadiusClass)}
/>
);
}, [src, children, title, subtitle, borderRadiusClass]);
return (
<Button
type="button"
disabled={disabled}
variant="outline"
className={cn(
'hover:border-primary hover:bg-accent flex h-fit w-full flex-col items-center justify-center border-dashed',
borderRadiusClass,
src ? 'p-0.5' : 'px-0 py-3',
isDragActive && 'border-primary',
className
)}
{...getRootProps()}
>
<input {...getInputProps()} />
{renderContent()}
</Button>
);
};
Update the import paths to match your project setup.
Usage
import { ImageDropzone } from '@kit/ui/image-dropzone';
<ImageDropzone
borderRadius="md"
onDrop={(accepted) => {
const first = accepted[0];
if (first) {
const url = URL.createObjectURL(first);
console.log('Dropped file URL:', url);
}
}}
/>
Features
- Drag & drop integration
- Optional preview via
src
prop - Border radius presets and easy styling
API Reference
Prop | Type | Default |
---|---|---|
title | string | |
subtitle | string | |
src | string | |
borderRadius | "none" | "sm" | "md" | "lg"... | |
className | string | |
onDrop | function | |
onError | function | |
children | React.ReactNode |
File Upload
A simple file input with validation for formats and size.
Media Manager
A full-featured media picker and manager with selection, edit, and upload.
How is this guide?
Last updated on 10/17/2025