Skip to content

Actions

Drop Zone

A surface that accepts files dropped from the desktop.

When to use it: Use it when dragging files is a convenient alternative to choosing them in a file picker.

On this page

Example

Drop PNG or JPEG images here

No images selected

Drop Zone.tsxtsx
import { useState } from "react";
import { DropZone, FileTrigger } from "@comp0/react";
import { ArrowUpTrayIcon } from "@heroicons/react/20/solid";

export function Example() {
  const [files, setFiles] = useState<string[]>([]);
  const updateFiles = (selected: File[]) => setFiles(selected.map((file) => file.name));

  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <DropZone
        accept="image/png,image/jpeg"
        onDrop={updateFiles}
        className="flex min-h-40 flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed border-zinc-950/20 p-6 text-center transition-colors data-accept:border-teal-600 data-accept:bg-teal-50 data-reject:border-red-600 data-reject:bg-red-50 dark:border-white/20 dark:data-accept:border-teal-400 dark:data-accept:bg-teal-950/40 dark:data-reject:border-red-400 dark:data-reject:bg-red-950/40"
      >
        <ArrowUpTrayIcon className="size-6 text-zinc-500" aria-hidden="true" />
        <p className="text-sm text-zinc-600 dark:text-zinc-300">Drop PNG or JPEG images here</p>
        <FileTrigger
          accept="image/png,image/jpeg"
          multiple
          className="cursor-pointer rounded bg-zinc-900 px-3 py-2 text-sm text-white has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-teal-600 dark:bg-zinc-100 dark:text-zinc-950 dark:has-focus-visible:outline-teal-400"
          onChange={(event) => updateFiles([...(event.currentTarget.files ?? [])])}
        >
          Choose images
        </FileTrigger>
      </DropZone>
      <p className="text-sm text-zinc-600 dark:text-zinc-400" aria-live="polite">
        {files.length ? files.join(", ") : "No images selected"}
      </p>
    </div>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. DropZone

    Native div that accepts matching files dropped from outside the page. Owns a DOM element.

  2. FileTriggerOptional

    Optional native file chooser using the same accept filter. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start with a DropZone and explain which files it accepts in visible text.

  2. 2

    Add the supporting parts

    Add a FileTrigger inside it so keyboard and touch users can choose the same files.

  3. 3

    Make the behavior clear

    Use accept on both parts and handle accepted and rejected drops separately when the distinction matters.

    Exampletsx
    <DropZone accept="image/*" onDrop={upload}>
      <FileTrigger accept="image/*">Choose images</FileTrigger>
    </DropZone>;

Keyboard

Forms and accessibility

DropZone does not create form values. FileTrigger submits selected files with its native name prop.

Accessibility checklist

  • Describe accepted files in visible text; accept filters files but does not name the task for assistive technology.
  • Always include FileTrigger or another keyboard-reachable file chooser; dropping is pointer-only.
  • Show rejected files and upload errors in text, not only through the drop zone color.

API reference

Importtsx
import { DropZone, FileTrigger } from "@comp0/react";

DropZone

DOM element

Native div that accepts matching files dropped from outside the page.

PropTypeDescription
acceptstringComma-separated MIME types, wildcards, or file extensions.
onDrop(files: File[]) => voidReceives files only when every file matches accept.
onDropRejected(files: File[]) => voidReceives files when one or more files do not match accept.
disabledbooleanStops the zone from accepting file drags or drops.

FileTrigger

OptionalDOM element

Optional native file chooser using the same accept filter.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

DropZone

Style hookMeaning
[data-active]A file drag is over the zone.
[data-accept]The dragged files match accept.
[data-reject]One or more dragged files do not match accept.
[data-disabled]The zone ignores file drops.

Keep exploring