FileUpload
Anatomy
+-------------------------------------------+| Label || +-------------------------------------+ || | | | ← dashed dropzone| | Click to upload or drag-and-drop | || | · .pdf, .docx · up to 10 MB | || | | || +-------------------------------------+ || optional description || || [ report-q3.pdf 2.4 MB × ] | ← file list| ▓▓▓▓▓▓▓▓░░░░░░░░░░ 63% |+-------------------------------------------+When to use
- Any place users attach a file: avatar upload, attachment to a message, CSV import, document upload.
- Pair with
<AttachmentTile>if you want a post-upload view with rich previews.
Examples
Single file, size-bounded
<FileUpload label="Logo" accept="image/png,image/svg+xml" maxSize={2 * 1024 * 1024} onFiles={([file]) => upload(file)}/>Multiple files with progress
const [progress, setProgress] = useState<Record<string, number>>({});
<FileUpload multiple accept=".pdf,.docx" onFiles={(files) => files.forEach((f) => uploadWithProgress(f, (pct) => { setProgress((p) => ({ ...p, [f.name]: pct })); }))} progress={progress}/>Wired to react-hook-form
const { setValue, watch } = useFormContext<{ files: File[] }>();
<FileUpload label="Attachments" multiple onFiles={(files) => setValue('files', [...(watch('files') ?? []), ...files])}/>Tokens
See the tokens block in this spec’s frontmatter.
Install: @helixui/core
import { FileUpload } from '@helixui/core'status: stable · since: 0.1.0
Tags: file, upload, dropzone, attachment, drag-drop, input
Props
| Name | Type | Default | Description |
|---|---|---|---|
label | string | undefined | Field label rendered above the dropzone. |
description | ReactNode | undefined | Helper text rendered below the dropzone. |
hint | ReactNode | undefined | Visible inside the dropzone — defaults to a “Click to upload or drag and drop” cue. |
accept | string | undefined | MIME / extension filter; e.g. “image/*” or “.pdf,.docx”. |
maxSize | number | undefined | Max file size in bytes. Files larger are reported via onReject. |
multiple | boolean | false | Allow selecting more than one file. |
onFiles | (files: File[]) => void | undefined | Fires when files pass the accept + size filters. |
onReject | (rejections: { file: File; reason: 'size' | 'type' }[]) => void | undefined | Fires for files that fail filtering. |
progress | Record<string, number> | undefined | Map of file.name → 0-100 percent. helixui renders a progress bar per file. |
errors | Record<string, string> | undefined | Optional per-file error messages, keyed by file.name. |
tone | 'brand' | 'neutral' | brand | Tone for the active drop ring. |
disabled | boolean | false | Disable interaction. |
Tokens used
color.bg.surface.default, color.bg.surface.subtle, color.bg.action.brand.subtle, color.bg.action.brand.default, color.border.subtle, color.border.action.brand, color.text.primary, color.text.secondary, color.text.muted, color.text.action.brand, color.text.danger, radius.sm, radius.md, radius.lg, spacing.1, spacing.2, spacing.3, spacing.5, font.size.xs, font.size.sm, font.weight.medium, font.weight.semibold
Accessibility
Role: button
Keyboard
| Key | Action |
|---|---|
Tab | Focus the dropzone. |
Enter | Open the native file picker. |
Space | Open the native file picker. |
Notes
- The dropzone is a labeled button (
role="button") for screen readers. - Drag-and-drop is a supplementary affordance; keyboard + native picker is the primary path.
- Each progress bar exposes ARIA progress state with min/max/value.
- Disabled state removes the dropzone from the tab order.