Dropzone
Forms
Drag-and-drop uploader with pixel borders, helper messaging, and removable previews.
Import
import { PixelDropzone } from "@/components/ui/pixel/pixel-dropzone"Usage
Upload Assets
PNG, GIF or WEBP up to 10MB
Component Source
Copy and paste the following code into your project at /src/components/ui/pixel/pixel-dropzone.tsx
"use client";
import { FileText, Image as ImageIcon, UploadCloud, X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
type FileRenderer = (file: File, index: number) => React.ReactNode;
type PixelDropzoneProps = {
label?: React.ReactNode;
description?: React.ReactNode;
helperText?: React.ReactNode;
hasError?: boolean;
accept?: string | string[];
maxFiles?: number;
multiple?: boolean;
disabled?: boolean;
files?: File[];
defaultFiles?: File[];
renderFile?: FileRenderer;
onFilesChange?: (files: File[]) => void;
onFileRemove?: (file: File, index: number) => void;
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
className?: string;
dropzoneClassName?: string;
helperClassName?: string;
};
function normalizeAccept(accept?: string | string[]) {
if (!accept) return undefined;
const list = Array.isArray(accept) ? accept : accept.split(",");
return list.map((entry) => entry.trim()).filter(Boolean);
}
function matchesAccept(file: File, acceptList?: string[]) {
if (!acceptList?.length) return true;
return acceptList.some((rule) => {
if (rule.startsWith(".")) {
return file.name.toLowerCase().endsWith(rule.toLowerCase());
}
if (rule.endsWith("/*")) {
const prefix = rule.slice(0, -1);
return file.type.startsWith(prefix.slice(0, -1));
}
return file.type === rule;
});
}
// ... (more code below)Props
| Prop | Type | Default | Description |
|---|---|---|---|
| accept | string | string[] | - | Accepted MIME types or file extensions. |
| maxFiles | number | - | Maximum number of files that can be queued. |
| multiple | boolean | true | Allow selecting multiple files at once. |
| files | File[] | - | Controlled list of files for preview rendering. |
| onFilesChange | (files: File[]) => void | - | Callback fired whenever the selection changes. |
| helperText | React.ReactNode | - | Helper or status text displayed below the dropzone. |
| hasError | boolean | false | Tints the helper text and border for error states. |
Examples
Basic Image Upload
Upload Assets
PNG, GIF or WEBP up to 10MB
Custom Preview
Upload Assets
PNG, GIF or WEBP up to 10MB
Accessibility
This component is built with accessibility in mind, including proper ARIA attributes, keyboard navigation, and focus management.