# Dropzone

> Cherry Dropzone component - a file input drop target with drag & drop, validation, and preview thumbnails.

Source: https://cherry.al/code/dropzone

> For the complete documentation index, see [llms.txt](https://cherry.al/llms.txt).

# Dropzone

<iframe className="light-only" src="https://demo.cherry.al/preview/dropzone?theme=light" title="Dropzone" loading="lazy" style={{ width: "100%", height: "400px", border: "1px solid var(--color-grayLight)", borderRadius: "12px" }} />
<iframe className="dark-only" src="https://demo.cherry.al/preview/dropzone?theme=dark" title="Dropzone" loading="lazy" style={{ width: "100%", height: "400px", border: "1px solid var(--color-grayLight)", borderRadius: "12px" }} />

<iframe className="light-only" src="https://demo.cherry.al/preview/dropzone-inline?theme=light" title="Inline dropzone" loading="lazy" style={{ width: "100%", height: "320px", border: "1px solid var(--color-grayLight)", borderRadius: "12px" }} />
<iframe className="dark-only" src="https://demo.cherry.al/preview/dropzone-inline?theme=dark" title="Inline dropzone" loading="lazy" style={{ width: "100%", height: "320px", border: "1px solid var(--color-grayLight)", borderRadius: "12px" }} />

The Dropzone component is a file input rendered as a dashed drop target. It supports click-to-browse and drag & drop, validates files against `accept`, `$maxFiles`, and `$maxBytes`, and shows preview thumbnails with remove buttons for the selected files.

The upload itself stays in your hands: the component only manages the file list and hands you `File` objects.

For design guidelines and all interactive states, see the [Inputs](/inputs) design page.

```jsx
import React from "react";
import { Dropzone } from "cherry-styled-components";

export default function Page() {
  return (
    <Dropzone
      accept="image/png,image/jpeg,image/webp"
      multiple
      $maxFiles={5}
      $maxBytes={5 * 1024 * 1024}
      $prompt="Drag images here"
      $browse="or click to browse"
      $hint="PNG, JPG or WebP · up to 5MB · max 5 files"
      $icon="ImageUp"
      onFilesChange={(files) => console.log(files)}
      onFilesRejected={(rejections) => console.warn(rejections)}
    />
  );
}
```

The inline variant is a compact horizontal row with a transparent background for embedding inside forms or modals. Without `multiple`, selecting a new file replaces the current one:

```html
<Dropzone $inline accept="image/*" $prompt="Drag an image here" />
```

## Properties

<Field value="$prompt" type="string">
  Bold primary prompt line. Defaults to `"Drag & drop files here"`.
</Field>

<Field value="$browse" type="string">
  Optional "or click to browse" sub-line beneath the prompt.
</Field>

<Field value="$hint" type="string">
  Optional smaller hint line for accepted types and limits.
</Field>

<Field value="$icon" type="IconProps">
  Name of the Lucide icon shown in the rounded tile. `IconProps` is a string union of all Lucide icon names, not an object. Defaults to `"FileUp"`.
</Field>

<Field value="$inline" type="boolean">
  Compact horizontal variant with a transparent background.
</Field>

<Field value="$maxFiles" type="number">
  Maximum number of files kept at once (with `multiple`).
</Field>

<Field value="$maxBytes" type="number">
  Maximum size per file in bytes.
</Field>

<Field value="onFilesChange" type="(files: File[]) => void">
  Called with the full current file list whenever it changes.
</Field>

<Field value="onFilesRejected" type="(rejections: DropzoneRejection[]) => void">
  Called with the rejected files and a typed reason (`"type"`, `"size"`, or
  `"count"`) so you can surface errors however you like, for example with a
  Toast.
</Field>

<Field value="accept" type="string">
  Native accept filter. Also enforced for dropped files, including `.ext` and
  `type/*` patterns.
</Field>

<Field value="multiple" type="boolean">
  Allows selecting several files. Without it, a new file replaces the current
  one.
</Field>

<Field value="disabled" type="boolean">
  Disables the whole control: click-to-browse, drag & drop, and the thumbnail
  remove buttons stop working, and the drop target gets disabled styling. The
  drop target also disables itself once the file limit is reached.
</Field>

All other native input attributes (`name`, `id`, `form`, `required`, and so
on) are passed through to the hidden `<input type="file" />`, and a `ref` is
forwarded to that same input.

## matchesAccept

The `matchesAccept(file, accept?)` helper the component uses to validate
dropped files is also exported. It checks a `File` against a comma-separated
`accept` string, supporting `.ext` suffixes, `type/*` wildcards, and exact MIME
types, and returns `true` when no `accept` string is given:

```jsx
import { matchesAccept } from "cherry-styled-components";

matchesAccept(file, ".pdf,image/*"); // true for report.pdf or photo.png
```

<Button href="https://github.com/cherry-design-system/styled-components/blob/main/src/lib/dropzone.tsx" icon="code" iconPosition="left">
  View Source
</Button>
