Studio
2

File Upload

Installation

pnpm dlx @mielui/svelte add file-upload

Upload behavior

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.

import * as FileUpload from '$lib/mielui/components/file-upload';

<FileUpload.Root
  accept="image/*,.pdf"
  maxSize={10 * 1024 * 1024}
  maxFiles={3}
  onUpload={async (file, { signal }) => {
      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.');
      }
  }}
/>

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}>
  {#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

In the first example, 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

SetmaxFiles={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.

API reference

FileUpload.Root

Validates selections and manages upload requests.

Prop Type Default
accept string | undefined —
maxSize number | undefined —
maxFiles number | undefined —
disabled boolean | undefined false
onUpload Required (file: File, options: { signal: AbortSignal; onProgress: (percent: number) => void; }) => Promise<void> —
children Snippet<[FileUploadSummary]> | undefined —

FileUpload.Details

Shows filename and size.

FileUpload.Dropzone

Displays the drop target.

FileUpload.Item

Provides one upload state to its parts.

Prop Type Default
item Required { readonly id: string; readonly file: File; readonly status: "uploading" | "complete" | "error"; readonly progress?: number | undefined; readonly error?: string | undefined; readonly retryable: boolean; } —

FileUpload.List

Lists files and exposes each item to a snippet.

Prop Type Default
children Snippet<[FileUploadEntry]> | undefined —

FileUpload.Preview

Shows an image preview or file icon.

FileUpload.Progress

Displays progress during upload.

FileUpload.Remove

Cancels the request and removes its item.

Prop Type Default
children Snippet<[]> | undefined —
onkeydown ((event: KeyboardEvent) => void) | undefined —
onclick ((event: MouseEvent) => void) | undefined —
status ButtonStatus | undefined

Controlled visual state. Loading remains focusable and refuses activation.

—
disabled boolean | undefined —
variant ButtonVariant | undefined —
size "sm" | "md" | "lg" | "icon" | undefined —
element HTMLButtonElement | HTMLAnchorElement | undefined

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

—
unstyled boolean | undefined

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

—
loading boolean | undefined

Convenience alias for `status="loading"`.

—
loadingLabel string | undefined —
successLabel string | undefined —
errorLabel string | undefined —

FileUpload.Retry

Retries a failed request.

Prop Type Default
children Snippet<[]> | undefined —
onkeydown ((event: KeyboardEvent) => void) | undefined —
onclick ((event: MouseEvent) => void) | undefined —
status ButtonStatus | undefined

Controlled visual state. Loading remains focusable and refuses activation.

—
disabled boolean | undefined —
variant ButtonVariant | undefined —
size "sm" | "md" | "lg" | "icon" | undefined —
element HTMLButtonElement | HTMLAnchorElement | undefined

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

—
unstyled boolean | undefined

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

—
loading boolean | undefined

Convenience alias for `status="loading"`.

—
loadingLabel string | undefined —
successLabel string | undefined —
errorLabel string | undefined —

FileUpload.Status

Announces uploading, success, and errors.

FileUpload.Trigger

Opens the file picker.

Prop Type Default
children Snippet<[]> | undefined —
onkeydown ((event: KeyboardEvent) => void) | undefined —
onclick ((event: MouseEvent) => void) | undefined —
status ButtonStatus | undefined

Controlled visual state. Loading remains focusable and refuses activation.

—
disabled boolean | undefined —
variant ButtonVariant | undefined —
size "sm" | "md" | "lg" | "icon" | undefined —
element HTMLButtonElement | HTMLAnchorElement | undefined

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

—
unstyled boolean | undefined

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

—
loading boolean | undefined

Convenience alias for `status="loading"`.

—
loadingLabel string | undefined —
successLabel string | undefined —
errorLabel string | undefined —