Drag-and-drop upload area with a per-file list that shows file format, progress, and upload status.
Description
FileUpload is a compound component for uploading files. FileUpload owns the file list and the upload lifecycle; the drag-and-drop target is the free Dropzone (with a built-in trigger), and FileUploadList renders one FileUploadItem per file showing its format icon, name, transfer progress, and status (queued, uploading, paused, completed, or error).
It is managed by default: you pass an onUpload that performs the transfer and reports progress, and the component tracks files, validation, pause/resume, retry, and removal for you. Drop in a FileUploadList with no children and it renders every file automatically; compose FileUploadItem children yourself when you need a custom row. For fully custom UIs, the headless useFileUpload hook exposes the same state and actions.
Reach for it whenever users attach files: document uploads, image and media galleries, and attachment fields. For a single hidden file input with no list or progress, a plain Field with a native input is enough.
FileUpload is a Create UI Pro component. With a Pro seat, npx @create-ui/cli add file-upload installs it. The drop area is the standalone Dropzone — a free component FileUpload composes — and installing file-upload pulls it in automatically. The previews below are marked with a Pro badge.
Installation
Anatomy
FileUpload provides the upload context to its parts. Render a Dropzone and the list inside it; the list renders a row per file unless you pass your own FileUploadItem children.
For a custom row, compose the item parts and omit the ones you don't want:
Usage
Without an onUpload, accepted files stay in the queued state. accept, maxSize, and maxFiles reject non-matching files automatically and surface a message.
Examples
Sizes
The file list has its own size on FileUpload — sm (a single dense row per file) or lg (the default two-line row). It is set on the root and cascades to every FileUploadItem. The drop-area size is a separate axis on the Dropzone.
Upload states
Each row reflects its file's status: queued, uploading and paused (with a progress meter), completed (with a check), or error (with the rejection message). Pass file objects to FileUploadItem to render any status directly.
Completed actions
Set completedActions to reveal Change and Download buttons once a file finishes. Change re-picks a file and replaces it in place; Download saves it. At size="sm" they render as inline icon buttons instead of a bar. Override either with onReplace or onDownload.
Trigger only
Render a DropzoneTrigger on its own — a single button that opens the picker and feeds the same managed list, with no drop area.
Accessibility
Each row action is a real <button> with an aria-label. The drop area's own click, keyboard, and aria behaviour is documented on the Dropzone page.
ARIA notes:
- Status changes are announced through a built-in
aria-liveregion —politefor completed and removed files,assertivefor errors — so screen-reader users hear upload outcomes. - Removing a row moves focus to an adjacent row's controls (or the drop-area trigger), never to
<body>. - Each action button carries an
aria-label(Pause,Resume,Remove,Change,Download,Retry). - Animations respect
prefers-reduced-motion; the meter and status morphs collapse to instant state changes.
Styling
Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):
Data slots and attributes: the component sets these for CSS targeting.
data-slot="file-upload"on the root.data-slot="file-upload-list"on the list wrapper.data-slot="file-upload-item"withdata-status="<status>"anddata-sizeon each row.data-slot="file-upload-item-name",-icon,-status,-meta,-progress,-actions,-backgroundon the row parts.
The drop area's slots (dropzone, dropzone-trigger, ...) live on the Dropzone reference.
Target a specific status in CSS:
Related Components
- Dropzone: the free drag-and-drop target
FileUploadcomposes for its drop area. - Progress: the line and circular meters used for per-file upload progress.
- File Format: the file-type glyph rendered as each row's icon.
- Button: the trigger and row action buttons.
API Reference
FileUpload
Root that owns the file list and upload lifecycle and provides context to every part. Renders a <div data-slot="file-upload"> and extends React.ComponentProps<"div"> minus the hook option props listed below.
Props
Variants
Dropzone
The drop area is the free Dropzone component, composed inside FileUpload. When nested it inherits accept, maxSize, multiple, and disabled from the root and feeds accepted files straight into the list, so no wiring is needed. Its size (sm, md, lg) is independent of the list size. Use DropzoneTrigger on its own inside FileUpload for a picker button with no drop area. See the Dropzone reference for its props, subparts, sizes, and the useDropzone hook.
FileUploadList
Renders the rows. Renders a <div data-slot="file-upload-list"> and extends Omit<React.ComponentProps<"div">, "children">.
Props
FileUploadItem
A single file row. Renders a <div data-slot="file-upload-item" data-status data-size> and extends Omit<React.ComponentProps<"div">, "children">.
Props
Variants
useFileUpload
The headless hook behind FileUpload, for fully custom UIs. Accepts the same options FileUpload forwards and returns the file list plus actions. The drag, drop, and hidden-input handling live in the free useDropzone hook, which feeds accepted files in through onFilesAccepted.
Options
Returns
Types
Composition parts
Lower-level slots for custom rows. Each renders a styled <div> (or <p>) with a data-slot and merges className via cn(). For the drop area's parts (DropzoneHeader, DropzoneIcon, DropzoneTitle, and so on), see the Dropzone reference.