Dropzone
The drop area and the useUploadDropzone hook that the other upload components are built on.
dropzone.tsx exports:
Dropzone: a drop area that adds files to the nearestUploaderProvider.useUploadDropzone: react-dropzone'suseDropzone, connected to theUploaderProvider. It enforcesmaxFilesacross drops, adds what fits, and returns readable messages about skipped files.DropzonePrompt,DropzoneOverlayandUploadErrors: the building blocks for the empty state, the drag overlay and the error notice.dropzoneVariantsanddropzoneState: the classes for a drop area and the data attributes that drive its drag styles.
If you are installing the other upload components via the CLI, this component will be installed automatically. You can skip the following steps.
Installation
Use the shadcn CLI to add the component to your project.
npx shadcn@latest add https://edgestore.dev/r/dropzone.jsonUsage
Install or copy the component from Installation before using this example.
'use client';
import { Dropzone } from '@/components/upload/dropzone';
import {
UploaderProvider,
type UploadFn,
} from '@/components/upload/uploader-provider';
import { useEdgeStore } from '@/lib/edgestore';
import * as React from 'react';
export function DropzoneUsage() {
const { edgestore } = useEdgeStore();
const uploadFn: UploadFn = React.useCallback(
async ({ file, onProgressChange, signal }) => {
const res = await edgestore.publicFiles.upload({
file,
signal,
onProgressChange,
});
// you can run some server action or api here
// to add the necessary data to your database
console.log(res);
return res;
},
[edgestore],
);
return (
<UploaderProvider uploadFn={uploadFn} autoUpload>
<Dropzone
dropzoneOptions={{
maxFiles: 5,
maxSize: 1024 * 1024 * 2, // 2MB
accept: {
'image/*': ['.jpeg', '.jpg', '.png'],
},
typesLabel: 'JPG or PNG',
}}
/>
{/* You can create a component that uses the provider context */}
{/* (from the `useUploader` hook) to show a custom file list here */}
</UploaderProvider>
);
}Custom dropzones
Use useUploadDropzone to build your own drop area. Spread dropzoneState() on the root element so the data-dragging, data-rejected and data-disabled attributes drive the styles in dropzoneVariants:
import {
dropzoneState,
dropzoneVariants,
UploadErrors,
useUploadDropzone,
} from '@/components/upload/dropzone';
function MyDropzone() {
const { getRootProps, getInputProps, isDragActive, isDragReject, errors } =
useUploadDropzone({ maxFiles: 3, maxSize: 1024 * 1024 });
return (
<>
<div
{...getRootProps({ className: dropzoneVariants })}
{...dropzoneState({ isDragActive, isDragReject })}
>
<input {...getInputProps()} />
<p>Drop files here</p>
</div>
<UploadErrors errors={errors} />
</>
);
}upload-utils.ts has the helpers the components share: formatFileSize, accept presets (IMAGE_ACCEPT, DOCUMENT_ACCEPT, SPREADSHEET_ACCEPT), the minImageSize validator and the useObjectUrl preview hook.