

<Preview name="DropzoneWithFolderExample" />

## Overview [#overview]

The **Dropzone** component provides an accessible drag-and-drop area for file uploads. Built on React Aria, it includes keyboard navigation, screen reader support, and visual feedback for drag states. It supports multiple file selection, size and count limits, and integrates with the animated folder interaction for enhanced visual feedback. File type filtering is handled by the browser's native file picker via the `accept` prop — no runtime MIME type validation is performed.

## Usage [#usage]

Dropzone provides the drag-and-drop behavior and file picker. Use [EmptyState](/primitives/empty-state) sub-components for the visual content inside.

```tsx
import {
  Dropzone,
  DropzoneAction,
  DropzoneFolderAnimation,
  EmptyStateMedia,
  EmptyStateHeading,
  EmptyStateTitle,
  EmptyStateDescription,
} from "@tilt-legal/cubitt-components/primitives";
```

```tsx
<Dropzone onFileDrop={(files) => console.log(files)}>
  <EmptyStateMedia>
    <CloudUpload />
  </EmptyStateMedia>
  <EmptyStateHeading>
    <EmptyStateTitle>Drop files here</EmptyStateTitle>
    <EmptyStateDescription>or click to browse</EmptyStateDescription>
  </EmptyStateHeading>
</Dropzone>
```

## Examples [#examples]

### With Action Button [#with-action-button]

Add a clickable button inside the dropzone to open the file picker dialog.

<Tabs className="bg-transparent border-none rounded-none" items="['Preview', 'Code']">
  <Tab value="Preview" className="p-0">
    <Preview name="DropzoneWithActionExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      Button,
      Dropzone,
      DropzoneAction,
      EmptyStateMedia,
      EmptyStateHeading,
      EmptyStateTitle,
      EmptyStateDescription,
    } from "@tilt-legal/cubitt-components/primitives";
    import {
      DropzoneFolderAnimation,
      EmptyStateHeading,
      EmptyStateTitle,
      EmptyStateDescription,
    } from "@tilt-legal/cubitt-components/primitives";
    import {
      CloudUpload } from "@tilt-legal/cubitt-icons/ui/outline";

    <Dropzone onFileDrop={(files) => console.log(files)}>
      <EmptyStateMedia>
        <CloudUpload />
      </EmptyStateMedia>
      <EmptyStateHeading>
        <EmptyStateTitle>Drag and drop files</EmptyStateTitle>
        <EmptyStateDescription>
          PDF,
      DOCX,
      or images up to 10MB
        </EmptyStateDescription>
      </EmptyStateHeading>
      <DropzoneAction>
        <Button variant="outline" size="sm">
          Browse Files
        </Button>
      </DropzoneAction>
    </Dropzone>;
    ```
  </Tab>
</Tabs>

### With Folder Animation [#with-folder-animation]

Use the animated folder component for enhanced visual feedback. The folder opens when files are dragged over the dropzone. When an `accept` prop is set on the parent `Dropzone`,
file type icons are automatically shown on the document pages.

<Tabs
  className="bg-transparent border-none rounded-none"
  items="['Preview',
'Code']"
>
  <Tab value="Preview" className="p-0">
    <Preview name="DropzoneFolderWithIconsExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import { Dropzone } from "@tilt-legal/cubitt-components/primitives";

    <Dropzone
      accept={[".pdf", ".docx", ".xlsx"]}
      onFileDrop={(files) => console.log(files)}
    >
      <DropzoneFolderAnimation />
      <EmptyStateHeading>
        <EmptyStateTitle>Upload documents</EmptyStateTitle>
        <EmptyStateDescription>
          PDF, Word, and Excel files accepted
        </EmptyStateDescription>
      </EmptyStateHeading>
    </Dropzone>;
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### Dropzone [#dropzone]

Root component that handles drag-and-drop and file selection.

| Prop               | Type                                    | Default     | Description                                                                                              |
| ------------------ | --------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------- |
| `onFileDrop`       | `(files: File[]) => void`               | -           | Callback when valid files are dropped or selected                                                        |
| `onFilesRejected`  | `(rejections: FileRejection[]) => void` | -           | Callback when files are rejected (size or count)                                                         |
| `accept`           | `string \| string[]`                    | -           | Passed to the native file input to filter the browser's file picker. No runtime validation is performed. |
| `multiple`         | `boolean`                               | `true`      | Allow multiple file selection                                                                            |
| `maxSize`          | `number`                                | -           | Maximum file size in bytes                                                                               |
| `maxFiles`         | `number`                                | -           | Maximum number of files allowed                                                                          |
| `isDisabled`       | `boolean`                               | `false`     | Disable the dropzone                                                                                     |
| `variant`          | `"default" \| "minimal" \| "ghost"`     | `"default"` | Visual variant style                                                                                     |
| `getDropOperation` | `(types) => DropOperation`              | -           | Custom function to determine drop operation                                                              |
| `onDrop`           | `(e: DropEvent) => void`                | -           | Raw drop event callback (from React Aria)                                                                |
| `children`         | `ReactNode`                             | -           | Composable sub-components                                                                                |
| `className`        | `string`                                | -           | Additional CSS classes                                                                                   |

#### FileRejection Type [#filerejection-type]

```tsx
type FileRejection = {
  file: File;
  reason: "size" | "count";
  message: string;
};
```

### DropzoneFolderAnimation [#dropzonefolderanimation]

Animated folder component with documents that fan out when opened. Automatically responds to drag events when used inside a `Dropzone`.

| Prop                | Type      | Default | Description                                                     |
| ------------------- | --------- | ------- | --------------------------------------------------------------- |
| `showFileTypeIcons` | `boolean` | `true`  | Show file type icons on documents based on parent `accept` prop |
| `className`         | `string`  | -       | Additional CSS classes                                          |

The folder automatically opens when files are dragged over the parent `Dropzone`.

### DropzoneAction [#dropzoneaction]

Wrapper for action buttons. Handles click propagation to open the file picker.

| Prop        | Type        | Default | Description                   |
| ----------- | ----------- | ------- | ----------------------------- |
| `children`  | `ReactNode` | -       | Button or interactive element |
| `className` | `string`    | -       | Additional CSS classes        |
