File Upload
Drop your files here
or choose them from your device.
Installation
npx @mielui/svelte add file-uploadyarn dlx @mielui/svelte add file-uploadbunx @mielui/svelte add file-uploadUsage
Root validates each selection, then calls onUpload for each accepted file. Resolve the promise only after your server confirms the upload. Throw an error to show a retryable failure. Report real progress from 0 to 100 with onProgress, or omit it for an indeterminate upload. The component does not invent progress or choose an upload endpoint.
Pass signal to your request. Removing an active file and unmounting Root abort pending requests. Removing a completed item clears it locally; your application owns deleting server files. Retry uses the same file with a fresh signal. Rejected file types, oversized files, duplicates, and excess files remain visible without a retry action. Validate files on your server too.
<script lang="ts">
import * as FileUpload from '@mielui/svelte/components/file-upload';
type UploadOptions = Parameters<FileUpload.FileUploadProps['onUpload']>[1];
async function upload(file: File, { signal }: UploadOptions) {
const body = new FormData();
body.append('file', file);
const response = await fetch('/api/uploads', {
method: 'POST',
body,
signal
});
if (!response.ok) {
throw new Error('Upload failed. Try again.');
}
}
</script>
<FileUpload.Root
accept="image/*,.pdf"
maxSize={10 * 1024 * 1024}
maxFiles={3}
onUpload={upload}
/>Compose the card
Root exposes items, total, uploading, and complete through its children snippet. List exposes each item. Item provides its state to Preview, Details, Progress, Status, Retry, and Remove. The default composition uses these same parts. This example omits the preview and puts status above progress.
<FileUpload.Root onUpload={upload}>
{#snippet children({ complete, total })}
<FileUpload.Dropzone>
<p>Drop project files here</p>
<FileUpload.Trigger>Browse files</FileUpload.Trigger>
</FileUpload.Dropzone>
<p>{complete} of {total} uploaded</p>
<FileUpload.List>
{#snippet children(item)}
<FileUpload.Item {item}>
<div class="min-w-0 flex-1">
<FileUpload.Details />
<FileUpload.Status />
<FileUpload.Progress />
</div>
<FileUpload.Retry />
<FileUpload.Remove />
</FileUpload.Item>
{/snippet}
</FileUpload.List>
{/snippet}
</FileUpload.Root>Motion and accessibility
The dropzone, file list, progress, and completion state animate in place. Animation respects reduced motion and the theme's panel duration. Choose files works with a keyboard; status changes are announced, and icon actions include tooltips.
Retry and cancellation
Turn on "Fail the next upload" before choosing a file. Retry keeps the original file and starts a new request. Remove cancels a pending upload and removes its card. Your upload handler must pass the supplied signal to fetch or abort its own transport when the signal fires.
Project files
Images and PDFs. Up to 3 files, 10 MB each.
Drop your files here
or choose them from your device.
Demo only. Files stay on your device.
Progress measures bytes sent, not server acceptance. Keep the promise pending until the server confirms completion. An image preview stays attached to the same file during progress updates and releases its object URL when removed. A rejected oversized image is shown as an error without decoding a preview.
Single file
Set maxFiles={1}
to accept one file and use a single-file picker. Remove the current photo before
choosing its replacement. Dropping extra files keeps the accepted file and shows why the
others were rejected. This example creates a local preview only.
Profile photo
One PNG, JPEG, or WebP, up to 5 MB.
Local preview only. This example does not upload your file.
Labels
Built-in text is English. Pass a labels object to Root to translate or reword the dropzone, the buttons, upload status, and validation errors. FileUploadLabels types it; every key is optional. Keys that include a value, such as tooMany and tooLarge, take a function. uploadFailed is shown when an upload throws without a message.
<FileUpload.Root
onUpload={upload}
labels={{
dropzoneTitle: 'Dรฉposez vos fichiers ici',
choose: 'Choisir des fichiers',
tooMany: (max) => `${max} fichiers au maximum.`
}}
/>Buttons and the disabled state
Set disabled on Root to stop new files from being chosen or dropped, for example while a form is submitting. Files already in the list stay where they are.
Trigger, Retry and Remove are built on Button, so they accept its props. variant and size change the look and disabled blocks activation. loading shows a spinner and ignores clicks, and labels sets the text for each state. unstyled removes the Button classes so class alone styles the part. onclick and onkeydown run before the part does its own work. element binds the DOM node of each one.
Attachments
Uploads are locked.
API reference
FileUpload.Root
Validates selections and manages upload requests.
labelsFileUploadLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
acceptstringAccepted file types, written as for a file input.
maxSizenumberLargest file size in bytes.
maxFilesnumberLargest number of files.
disabledbooleanPrevents interaction and dims the control.
Default
falseonUploadRequired(file: File, options: { signal: AbortSignal; onProgress: (percent: number) => void; }) => Promise<void>Uploads one file. Report progress with
onProgressand stop whensignalaborts.childrenSnippet<[FileUploadSummary]>Content rendered inside.
FileUpload.Item
Provides one upload state to its parts.
itemRequired{ readonly id: string; readonly file: File; readonly status: "uploading" | "complete" | "error"; readonly progress?: number | undefined; readonly error?: string | undefined; readonly retryable: boolean; }Upload entry from the Root's list.
FileUpload.List
Lists files and exposes each item to a snippet.
childrenSnippet<[FileUploadEntry]>Content rendered inside.
FileUpload.Remove
Cancels the request and removes its item.
childrenSnippet<[]>Content rendered inside.
onkeydown((event: KeyboardEvent) => void)Called on key down, before the button handles the key itself.
onclick((event: MouseEvent) => void)Called when the button is activated. Loading and disabled buttons do not call it.
statusButtonStatusControlled visual state. Loading remains focusable and refuses activation.
disabledbooleanPrevents activation. A disabled link loses its destination and is skipped by Tab.
variantButtonVariantVisual style. Choose it for what the action means, not for decoration.
size"sm" | "md" | "lg" | "icon"Control height.
iconis a square button for a single icon.elementHTMLButtonElement | HTMLAnchorElementBindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:
unstyledbooleanSkip the variant/size base classes and render with
classalone.loadingbooleanConvenience alias for
status="loading".labelsButtonLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
FileUpload.Retry
Retries a failed request.
childrenSnippet<[]>Content rendered inside.
onkeydown((event: KeyboardEvent) => void)Called on key down, before the button handles the key itself.
onclick((event: MouseEvent) => void)Called when the button is activated. Loading and disabled buttons do not call it.
statusButtonStatusControlled visual state. Loading remains focusable and refuses activation.
disabledbooleanPrevents activation. A disabled link loses its destination and is skipped by Tab.
variantButtonVariantVisual style. Choose it for what the action means, not for decoration.
size"sm" | "md" | "lg" | "icon"Control height.
iconis a square button for a single icon.elementHTMLButtonElement | HTMLAnchorElementBindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:
unstyledbooleanSkip the variant/size base classes and render with
classalone.loadingbooleanConvenience alias for
status="loading".labelsButtonLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
FileUpload.Trigger
Opens the file picker.
childrenSnippet<[]>Content rendered inside.
onkeydown((event: KeyboardEvent) => void)Called on key down, before the button handles the key itself.
onclick((event: MouseEvent) => void)Called when the button is activated. Loading and disabled buttons do not call it.
statusButtonStatusControlled visual state. Loading remains focusable and refuses activation.
disabledbooleanPrevents activation. A disabled link loses its destination and is skipped by Tab.
variantButtonVariantVisual style. Choose it for what the action means, not for decoration.
size"sm" | "md" | "lg" | "icon"Control height.
iconis a square button for a single icon.elementHTMLButtonElement | HTMLAnchorElementBindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:
unstyledbooleanSkip the variant/size base classes and render with
classalone.loadingbooleanConvenience alias for
status="loading".labelsButtonLabelsOverrides the built-in text and accessible names. Every key is optional and English is the fallback.
Other parts
These parts have no props of their own. They pass HTML attributes and events to their element.
FileUpload.DetailsShows filename and size.FileUpload.DropzoneDisplays the drop target.FileUpload.PreviewShows an image preview or file icon.FileUpload.ProgressDisplays progress during upload.FileUpload.StatusAnnounces uploading, success, and errors.
pnpm dlx @mielui/svelte add file-upload