# FileDrop

> A drop zone and file picker with type and size checks and per-file status chips.

Category: Forms. Docs page: https://rime.mjsons.net/components/file-drop

## Installation

```bash
npx shadcn@latest add KezLahd/rime/file-drop
```

FileDrop validates type and size client-side, lists files as FileChips with uploading, done and error states, and keeps a real file input for keyboard users.

## Usage

```tsx
import { FileDrop } from "@/components/ui";

<FileDrop files={files} onFilesChange={setFiles} accept={[".pdf"]} multiple={false} />
```

## Props: FileDrop

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `files` (required) | `File[]` |  |  |
| `onFilesChange` (required) | `(files: File[]) => void` |  |  |
| `accept` | `string[]` | `[".pdf", ".jpg", ".jpeg", ".png"]` | Extensions including the dot. Checked by name and MIME type both. |
| `maxSizeBytes` | `number` | `10 * 1024 * 1024` |  |
| `multiple` | `boolean` | `true` |  |
| `disabled` | `boolean` |  |  |
| `invalid` | `boolean` |  |  |
| `title` | `ReactNode` | `"Drop the file here"` |  |
| `description` | `ReactNode` |  | Defaults to a sentence built from accept and maxSizeBytes. |
| `statusFor` | `(file: File) => Pick<FileChipProps, "status" \| "message"> \| undefined` |  | Per-file upload state, keyed by file name. |
| `id` | `string` |  |  |
| `className` | `string` |  |  |
| `forceDragOver` | `boolean` | `false` | Holds the drag-over state without a drag. For the styleguide only. |

## Props: FileChip

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` (required) | `string` |  |  |
| `size` (required) | `number` |  |  |
| `status` | `"ready" \| "uploading" \| "done" \| "error"` | `"ready"` | ready = attached, not yet sent. |
| `message` | `ReactNode` |  | Shown under the name; required when status is "error". |
| `onRemove` | `() => void` |  |  |
| `className` | `string` |  |  |

## Examples

### Default

```tsx
<FileDrop files={files} onFilesChange={setFiles} />
```

## Theme tokens

System tokens it reads: `--brand`, `--brand-deep`, `--brand-fill`, `--brand-gradient`, `--brand-gradient-soft`, `--danger-field-fill`, `--danger-fill`, `--danger-ink`, `--danger-line`, `--dur`, `--ease`, `--focus-ring`, `--font-mono`, `--glow-sm`, `--ink-body`, `--ink-brand`, `--ink-disabled`, `--ink-heading`, `--ink-inverse`, `--ink-muted`, `--line-brand`, `--line-soft`, `--r-lg`, `--r-md`, `--r-xs`, `--rgb-brand`, `--rgb-brand-deep`, `--rgb-contact`, `--rgb-danger`, `--rgb-white`, `--success-fill`, `--success-ink`, `--surface-solid`, `--surface-sunken`, `--text-body`, `--text-caption`, `--text-small`.

## Accessibility

- The "Choose files" button opens the native picker; drag and drop is an enhancement, never the only way.

## Do

- State the accepted types and size limit in description.

## Don't

- Don't trust the client check; validate on the server too.
