Inputs

File Upload

Drop files, follow their progress, and retry failed uploads.

Installation

pnpm dlx @mielui/svelte add file-upload

Usage

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.

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.

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.

API reference

FileUpload.Root

Validates selections and manages upload requests.

  • labels
    FileUploadLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

  • accept
    string

    Accepted file types, written as for a file input.

  • maxSize
    number

    Largest file size in bytes.

  • maxFiles
    number

    Largest number of files.

  • disabled
    boolean

    Prevents interaction and dims the control.

    Default false

  • onUpload Required
    (file: File, options: { signal: AbortSignal; onProgress: (percent: number) => void; }) => Promise<void>

    Uploads one file. Report progress with onProgress and stop when signal aborts.

  • children
    Snippet<[FileUploadSummary]>

    Content rendered inside.

FileUpload.Item

Provides one upload state to its parts.

  • item Required
    { 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.

  • children
    Snippet<[FileUploadEntry]>

    Content rendered inside.

FileUpload.Remove

Cancels the request and removes its item.

  • children
    Snippet<[]>

    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.

  • status
    ButtonStatus

    Controlled visual state. Loading remains focusable and refuses activation.

  • disabled
    boolean

    Prevents activation. A disabled link loses its destination and is skipped by Tab.

  • variant
    ButtonVariant

    Visual style. Choose it for what the action means, not for decoration.

  • size
    "sm" | "md" | "lg" | "icon"

    Control height. icon is a square button for a single icon.

  • element
    HTMLButtonElement | HTMLAnchorElement

    Bindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:

  • unstyled
    boolean

    Skip the variant/size base classes and render with class alone.

  • loading
    boolean

    Convenience alias for status="loading".

  • labels
    ButtonLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

FileUpload.Retry

Retries a failed request.

  • children
    Snippet<[]>

    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.

  • status
    ButtonStatus

    Controlled visual state. Loading remains focusable and refuses activation.

  • disabled
    boolean

    Prevents activation. A disabled link loses its destination and is skipped by Tab.

  • variant
    ButtonVariant

    Visual style. Choose it for what the action means, not for decoration.

  • size
    "sm" | "md" | "lg" | "icon"

    Control height. icon is a square button for a single icon.

  • element
    HTMLButtonElement | HTMLAnchorElement

    Bindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:

  • unstyled
    boolean

    Skip the variant/size base classes and render with class alone.

  • loading
    boolean

    Convenience alias for status="loading".

  • labels
    ButtonLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

FileUpload.Trigger

Opens the file picker.

  • children
    Snippet<[]>

    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.

  • status
    ButtonStatus

    Controlled visual state. Loading remains focusable and refuses activation.

  • disabled
    boolean

    Prevents activation. A disabled link loses its destination and is skipped by Tab.

  • variant
    ButtonVariant

    Visual style. Choose it for what the action means, not for decoration.

  • size
    "sm" | "md" | "lg" | "icon"

    Control height. icon is a square button for a single icon.

  • element
    HTMLButtonElement | HTMLAnchorElement

    Bindable reference to the rendered DOM element. Type is the union of the two possible element types -- narrow at the use site:

  • unstyled
    boolean

    Skip the variant/size base classes and render with class alone.

  • loading
    boolean

    Convenience alias for status="loading".

  • labels
    ButtonLabels

    Overrides 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.Details Shows filename and size.
  • FileUpload.Dropzone Displays the drop target.
  • FileUpload.Preview Shows an image preview or file icon.
  • FileUpload.Progress Displays progress during upload.
  • FileUpload.Status Announces uploading, success, and errors.