File Upload
Drag-and-drop file picker with `accept` / `maxSize` / `maxFiles` validation, per-file progress and status, optional folder upload, and an async-cancellable remove hook.
Preview
Drag & drop a file here, or
Switch the framework picker (top-right of the panel) to render the same demo live in React, Vue, or Angular — same class names, ARIA, and visual output across all three.
Installation
Sisyphos UI ships unified packages for React, Vue, and Angular. Pick the one that matches your stack — every framework exports the same component classes, ARIA semantics, and CSS tokens.
$ pnpm add @sisyphos-ui/reactThen import the bundled stylesheet once at app entry: import "@sisyphos-ui/react/styles.css";
Usage
import { FileUpload } from "@sisyphos-ui/react";
export const Avatar = () => (
<FileUpload
label="Profile photo"
accept="image/*"
maxSize={2 * 1024 * 1024}
onChange={(files) => console.log(files)}
/>
);Max size with onReject
`maxSize` enforces a byte limit; `onReject` receives the rejection reason so you can show a friendly message.
Drag & drop a file here, or
Error state
Pair `error` with external error messaging for form validation.
Drag & drop a file here, or
Please attach your CV to continue.
API
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | UploadedFile[] | — | Controlled list of files, including pre-uploaded items (use `url` instead of `file`). |
| onChange* | (files: UploadedFile[]) => void | — | Called with the next file array after add or remove. |
| label | string | — | Field label rendered above the dropzone. |
| accept | string | — | MIME types or extensions accepted by the native input. |
| maxSize | number | 10 * 1024 * 1024 | Maximum byte size per file. |
| maxFiles | number | 1 | Maximum file count. With `1`, new uploads replace the existing entry. |
| multiple | boolean | — | Allow multi-select on the native input. Defaults to `maxFiles > 1`. |
| directory | boolean | false | Accepts an entire folder via `webkitdirectory`. Each picked file's `webkitRelativePath` is preserved. |
| supportedFormats | string[] | — | Human-readable formats shown below the dropzone. |
| onReject | (file: File, reason: RejectReason) => void | — | Called when a file fails type / size / count validation. |
| onBeforeRemove | (file: UploadedFile) => boolean | Promise<boolean> | — | Called before a file is removed. Returning `false` cancels the removal — useful for confirmations or revoking server-side resources first. |
| renderFile | (file, handlers) => ReactNode | — | Custom renderer for each file row. |
| labels | FileUploadLabels | — | i18n strings for placeholder, browse button, completed/uploading badges, and remove tooltip. |
| disabled | boolean | false | Disables the dropzone. |
| error | boolean | false | Marks the field as invalid for styling and ARIA. |
| errorMessage | string | — | Message shown below the dropzone when `error` is true. |
The full API including refs, ARIA attributes, and HTML passthroughs lives in the package README on npm.
Accessibility
- Native
<input type="file">is hidden but accessible via the surrounding label so screen readers announce the field correctly. - Each file row exposes a per-row remove button labeled via
labels.remove. - Drag state is reflected as a class on the dropzone for users with motion-aware themes.
Keyboard interactions
| Key | Action |
|---|---|
| Tab | Moves focus to the dropzone, then to each per-file remove button. |
| EnterthenSpace | Activates the focused control (open browser dialog, remove file). |