Skip to main content

Dropzone

A file upload component with drag-and-drop support, file validation, and upload progress tracking.

Props

upload
UseConvexUploadReturn
required
The return value from the useConvexUpload hook
className
string
Additional CSS classes to apply to the component

Hook: useConvexUpload

The component requires the useConvexUpload hook for managing file upload state.

Hook Options

allowedMimeTypes
string[]
default:"[]"
Allowed MIME types for file uploads. Supports wildcards (e.g., "image/*", "text/html"). Empty array allows all types.
maxFileSize
number
default:"Number.POSITIVE_INFINITY"
Maximum upload size per file in bytes (e.g., 1000 bytes = 1 KB)
maxFiles
number
default:"1"
Maximum number of files allowed per upload

Hook Return Values

files
FileWithPreview[]
Array of files selected for upload
setFiles
(files: FileWithPreview[]) => void
Function to update the files array
loading
boolean
Upload in progress state
errors
{ name: string; message: string }[]
Array of upload errors
successes
string[]
Array of successfully uploaded file names
isSuccess
boolean
True if all files uploaded successfully with no errors
onUpload
() => Promise<void>
Function to trigger file upload
maxFileSize
number
Maximum file size setting
maxFiles
number
Maximum files setting
allowedMimeTypes
string[]
Allowed MIME types setting
getRootProps
() => object
Props for the dropzone root element (from react-dropzone)
getInputProps
() => object
Props for the file input element (from react-dropzone)
isDragActive
boolean
True when files are being dragged over the dropzone
open
() => void
Function to programmatically open file picker

Types

interface FileWithPreview extends File {
  preview?: string;
  errors: readonly FileError[];
}

type UseConvexUploadOptions = {
  allowedMimeTypes?: string[];
  maxFileSize?: number;
  maxFiles?: number;
};

type UseConvexUploadReturn = ReturnType<typeof useConvexUpload>;

interface DropzoneProps {
  upload: UseConvexUploadReturn;
  className?: string;
}

Example

import { Dropzone } from "@/components/dropzone";
import { useConvexUpload } from "@/hooks/use-convex-upload";

export default function UploadPage() {
  const upload = useConvexUpload({
    allowedMimeTypes: ["image/*", "application/pdf"],
    maxFileSize: 5 * 1024 * 1024, // 5MB
    maxFiles: 3,
  });

  return (
    <div>
      <h1>Upload Files</h1>
      <Dropzone upload={upload} className="my-4" />
    </div>
  );
}

Direct Hook Usage

import { useConvexUpload } from "@/hooks/use-convex-upload";

export default function CustomUpload() {
  const {
    files,
    loading,
    errors,
    successes,
    isSuccess,
    onUpload,
    getRootProps,
    getInputProps,
    isDragActive,
  } = useConvexUpload({
    allowedMimeTypes: ["image/*"],
    maxFileSize: 10 * 1024 * 1024, // 10MB
    maxFiles: 5,
  });

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {isDragActive ? (
        <p>Drop files here...</p>
      ) : (
        <p>Drag files here or click to browse</p>
      )}
      
      {files.length > 0 && (
        <div>
          <h3>Selected Files:</h3>
          <ul>
            {files.map((file) => (
              <li key={file.name}>
                {file.name} - {file.size} bytes
                {successes.includes(file.name) && " ✓"}
              </li>
            ))}
          </ul>
          <button onClick={onUpload} disabled={loading || isSuccess}>
            {loading ? "Uploading..." : "Upload"}
          </button>
        </div>
      )}
      
      {errors.length > 0 && (
        <div>
          <h3>Errors:</h3>
          <ul>
            {errors.map((error) => (
              <li key={error.name}>
                {error.name}: {error.message}
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

Upload Flow

  1. Files are selected via drag-and-drop or file picker
  2. Files are validated against allowedMimeTypes, maxFileSize, and maxFiles
  3. Valid files are added to the files array with preview URLs (for images)
  4. Invalid files are added with their validation errors
  5. User clicks upload button (or calls onUpload())
  6. For each file:
    • Generate upload URL via generateUploadUrl mutation
    • Upload file to Convex storage via fetch POST
    • Save file metadata to database via saveFile mutation
  7. Track successes and errors per file
  8. Support partial uploads - can retry failed files

Features

  • Drag-and-drop support
  • File type validation with MIME types
  • File size validation
  • Maximum file count enforcement
  • Image preview generation
  • Upload progress tracking
  • Per-file error handling
  • Partial upload support (retry failed files)
  • Visual feedback for drag state, loading, success, and errors
  • File type icons for different MIME types

Build docs developers (and LLMs) love