A drop zone and file picker with type and size checks and per-file status chips.
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.
Installation
npx shadcn@latest add KezLahd/rime/file-dropAlso installs: base, button, field, icon, spinner.
Usage
import { FileDrop } from "@/components/ui";
<FileDrop files={files} onFilesChange={setFiles} accept={[".pdf"]} multiple={false} />Examples
Default
Drop the file here
PDF, JPG or PNG, up to 10 MB.
API
Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.
FileDrop
| Prop | Type | Default | Description |
|---|---|---|---|
| filesRequired | File[] | ||
| onFilesChangeRequired | (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. |
FileChip
| Prop | Type | Default | Description |
|---|---|---|---|
| nameRequired | string | ||
| sizeRequired | 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 |
Theme tokens
Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.
This component has no tokens of its own; it reads the system tokens below.
System tokens it reads
| Token | Default | Live value |
|---|---|---|
| --brand | tokens.css | … |
| --brand-deep | tokens.css | … |
| --brand-fill | tokens.css | … |
| --brand-gradient | tokens.css | … |
| --brand-gradient-soft | tokens.css | … |
| --danger-field-fill | tokens.css | … |
| --danger-fill | tokens.css | … |
| --danger-ink | tokens.css | … |
| --danger-line | tokens.css | … |
| --dur | tokens.css | … |
| --ease | tokens.css | … |
| --focus-ring | tokens.css | … |
| --font-mono | tokens.css | … |
| --glow-sm | tokens.css | … |
| --ink-body | tokens.css | … |
| --ink-brand | tokens.css | … |
| --ink-disabled | tokens.css | … |
| --ink-heading | tokens.css | … |
| --ink-inverse | tokens.css | … |
| --ink-muted | tokens.css | … |
| --line-brand | tokens.css | … |
| --line-soft | tokens.css | … |
| --r-lg | tokens.css | … |
| --r-md | tokens.css | … |
| --r-xs | tokens.css | … |
| --rgb-brand | tokens.css | … |
| --rgb-brand-deep | tokens.css | … |
| --rgb-contact | tokens.css | … |
| --rgb-danger | tokens.css | … |
| --rgb-white | tokens.css | … |
| --success-fill | tokens.css | … |
| --success-ink | tokens.css | … |
| --surface-solid | tokens.css | … |
| --surface-sunken | tokens.css | … |
| --text-body | tokens.css | … |
| --text-caption | tokens.css | … |
| --text-small | tokens.css | … |
Accessibility
- The "Choose files" button opens the native picker; drag and drop is an enhancement, never the only way.
Do and don't
Do
- State the accepted types and size limit in description.
Don't
- Don't trust the client check; validate on the server too.
For AI agents
This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.
Open file-drop.md