File Upload / Dropzone
Preview: Area
Drag-and-drop target plus a native file picker (React Aria DropZone + FileTrigger).
Import
import { FileDropZone, FileList } from '@marbleui/ui'
import { useFileUploads } from '@marbleui/ui'Props
<FileDropZone>
| Prop | Type | Default | Description |
|---|---|---|---|
| onFiles *required | (files: File[]) => void | — | |
| acceptedFileTypes | string[] | — | |
| allowsMultiple | boolean | true | |
| className | string | — | |
| hint | ReactNode | — | |
| title | ReactNode | 'Drop files here' | |
| variant | 'area' | 'compact' | 'area' | "area": large dashed drop target. "compact": a single row. |
<FileList>
| Prop | Type | Default | Description |
|---|---|---|---|
| files *required | UploadedFile[] | — | |
| className | string | — | |
| onRemove | (id: string) => void | — |
Hooks
useFileUploads(simulate?: boolean): { files: UploadedFile[]; add: (incoming: File[]) => void; remove: (id: string) => void; }Local state helper for demos and simple forms: adds files and fakes upload progress.
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria DropZone · React Aria FileTrigger · React Aria Text. Follow the primitive's docs for the full keyboard map.
Usage notes
Drag-and-drop file target plus picker (FileDropZone), a list of files (FileList) and a state helper (useFileUploads). For just a picker button use FileTrigger.
const { files, add, remove } = useFileUploads()
<FileDropZone onFiles={add} acceptedFileTypes={['image/*', 'application/pdf']} hint="PNG, JPG or PDF" />
<FileList files={files} onRemove={remove} />
FileDropZonefilters dropped and picked files byacceptedFileTypes(exact MIME types orimage/*style wildcards). SetallowsMultiple={false}for one file;variantisareaorcompact.useFileUploads()fakes progress by default. For real uploads passfalse(files count as done) or manage your ownUploadedFile[]withprogressanderror.- There is no size limit check: enforce it in
onFiles.
Example source · show· hide
import { FileDropZone, FileList, useFileUploads } from './file-upload'
function Area() {
const { files, add, remove } = useFileUploads()
return (
<div className="flex w-[26rem] flex-col gap-3">
<FileDropZone onFiles={add} hint="PNG, JPG or PDF, up to 10 MB" acceptedFileTypes={['image/*', 'application/pdf']} />
<FileList files={files} onRemove={remove} />
</div>
)
}
function Compact() {
const { files, add, remove } = useFileUploads()
return (
<div className="flex w-[26rem] flex-col gap-3">
<FileDropZone variant="compact" onFiles={add} title="Attach files" hint="Drag here or browse" />
<FileList files={files} onRemove={remove} />
</div>
)
}
function Avatar() {
const { files, add } = useFileUploads(false)
const last = files.at(-1)
return (
<div className="flex items-center gap-4">
<span className="grid size-16 place-items-center overflow-hidden rounded-full bg-surface-sunken text-xs text-fg-subtle">
{last ? <img src={URL.createObjectURL(last.file)} alt="" className="size-full object-cover" /> : 'None'}
</span>
<FileDropZone variant="compact" allowsMultiple={false} acceptedFileTypes={['image/*']} onFiles={add} title="Profile photo" hint="Square, at least 256px" />
</div>
)
}
export const styles = { Area, Compact, Avatar }Source: packages/ui/src/file-upload/file-upload.tsx
Catalog
- Category
- inputs
- Priority
- Foundation
- Primitive
- react-aria
- React Aria
- DropZone + FileTrigger