Source: https://monarchui.dev/components/upload-queue/

Components · Files

# UploadQueue

The list of uploads in flight: progress, status, cancel, retry, remove and a total summary.

@rookcom/monarch-react/collaboration

Component

## Mixed statuses

## Usage examples

### Without the header, with a custom step

## Purpose

Shows each file the product is uploading with its progress and status, lets people cancel, retry or remove uploads, and sums up the batch. Completion and failures are announced.

### Use when

- Several files upload at once, or uploads take long enough that people need to see progress.
- Uploads can fail for reasons people can act on (connection, size, quota) and should be retried.
- Pair with FileUpload, which hands over the files this list shows.

### Avoid when

- A single small file uploads in a moment: a loading button or Progress is enough.
- The list shows stored files rather than uploads in progress: use a file list or table.

## Design principles

- The product owns the transfer and the state; the queue only displays `items` and reports actions by id.
- Status is text and icon, never colour alone: "Uploading… 62%", "Uploaded", the error message.
- Actions appear only when they make sense and when the product handles them: cancel while active, retry for failed or cancelled uploads that can succeed, remove once finished.
- A refusal that cannot succeed unchanged (too large, wrong type) sets `retryable: false`, so Retry is not offered.
- Progress reuses Progress, so bars look and announce the same everywhere.

## API reference

```tsx
import { UploadQueue, countUploads, totalUploadProgress } from '@rookcom/monarch-react/collaboration';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `UploadQueue` | component | client | `.mn-upload-queue` |
| `countUploads` | utility | client | – |
| `totalUploadProgress` | utility | client | – |

Items are `{ id, name, status, size?, progress?, error?, retryable?, thumbnail?, icon?, detail? }`; `status` is `queued`, `uploading`, `done`, `failed` or `cancelled`, and `progress` is 0–100 (omit for an indeterminate bar).

`onCancel`, `onRetry` and `onRemove` receive the item id; each button appears only when its handler is given. `onClearFinished` adds a header button.

`countUploads(items)` and `totalUploadProgress(items)` are exported: the total leaves out failed and cancelled uploads and is weighted by size when every upload has one.

The ref is the root `<section>`; other attributes pass through.

Generated from the TypeScript declarations of `packages/react/src/components/files/upload-queue`.

## Properties

### `UploadQueue`

The list of files being uploaded: per-file progress and status, cancel, retry and remove, and a total summary. Completion and failures are announced. The product does the transfer and reports progress back.

| Prop | Type | Description |
| --- | --- | --- |
| `items` required | `readonly UploadQueueItem[]` | The uploads, in display order. The product updates status and progress. |
| `className` | `string` |  |
| `headingLevel` | `3 \| 4 \| 6 \| 2 \| 5` | Heading level of the title. Default 3. |
| `id` | `string` |  |
| `messages` | `Partial<UploadQueueMessages>` | Override labels and announcements. |
| `onCancel` | `((id: string) => void)` | Cancel a queued or uploading file. The button shows only when this is set. |
| `onClearFinished` | `(() => void)` | Remove every finished, failed and cancelled file. Shows a header button. |
| `onRemove` | `((id: string) => void)` | Remove a finished, failed or cancelled file from the list. |
| `onRetry` | `((id: string) => void)` | Retry a failed or cancelled file. |
| `showSummary` | `boolean` | Show the header with the title, summary and total progress. Default true. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `showSummary` | `'true'``'false'` | Show the header with title, summary ("1 of 4 uploaded · 1 failed") and total progress (default). Without it the section is named by `messages.title`. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Queued | `data-status="queued"` | "Waiting", with Cancel. |
| Uploading | `data-status="uploading"` | A Progress bar (determinate or indeterminate) and "Uploading… n%", with Cancel. |
| Done | `data-status="done"` | Success icon and "Uploaded", with Remove. |
| Failed | `data-status="failed"` | Error icon and the product’s message, with Retry (unless `retryable` is false) and Remove. |
| Cancelled | `data-status="cancelled"` | Muted name and "Cancelled", with Retry and Remove. |
| Active batch | `data-active` | Some uploads are queued or uploading; the header shows the total progress bar. |

## Interaction behaviour

- Buttons call the product’s handlers; the queue changes only when new `items` arrive.
- When a row is removed while focus is in it, focus moves to the next row (or the previous one, or the heading when the list is empty).
- Moving to done or failed is announced; when the last active upload finishes in a batch of several, a summary is announced too.
- `detail` replaces the status text, for extra steps such as "Checking for viruses".

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab | Moves between the Retry, Cancel and Remove buttons of each row, and Clear finished. |
| Enter / Space | Activates the focused button. |

## Accessibility

Role

region (section) labelled by its heading; a list of uploads

Accessible name

The heading, "Uploads" by default (

messages.title

).

- Each progress bar is named "Upload progress of {file}"; the total bar is "Total upload progress".
- Buttons are named with the file: "Cancel upload of photo.jpg", "Retry upload of photo.jpg", "Remove photo.jpg from the list". Retry keeps its visible word in its name.
- A polite live region announces completed and failed uploads and the end of the batch.
- Thumbnails are decorative (`alt=""`); the file name is the text.
- Verified with axe in jsdom and in Chromium, Firefox and WebKit on /components/upload-queue.

## Responsive behaviour

- Rows wrap: long names break anywhere, the size wraps under the name, and the actions stay at the end.
- The header wraps the Clear finished button and keeps the total bar full width. Works at 320px.

## Theme support

- Colours are Monarch semantic tokens only, so light, dark and more-contrast themes apply automatically.
- Done uses `--mn-color-success-strong`, failed `--mn-color-danger-strong`; both also have an icon and text.
- Progress bars follow Progress theming, including reduced motion for the indeterminate bar.

## Do and don't

### Do

- Report real progress (bytes sent) when you have it; omit `progress` rather than invent it.
- Write failure messages people can act on, and set `retryable: false` when retrying cannot help.
- Revoke object URLs you pass as `thumbnail` when the row is removed.

### Don't

- Do not remove failed uploads automatically; let people retry or dismiss them.
- Do not show refusals the FileUpload already explained as failed uploads.

## Related components

- [FileUpload](https://monarchui.dev/components/file-upload/): Picks and checks the files before they reach the queue.
- [Progress](https://monarchui.dev/components/progress-bar/): One progress bar for a single task.
- [Toast](https://monarchui.dev/components/toast/): A short confirmation once a background upload finishes, when no list is shown.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `react` |
| Monarch components | [Button](https://monarchui.dev/components/button/), [Progress](https://monarchui.dev/components/progress-bar/), [FileUpload](https://monarchui.dev/components/file-upload/) |

Uses `formatBytes` from FileUpload for sizes.

## Testing coverage

- Counting by status and the size-weighted total progress.
- Rows show status text, per-file and total progress, sizes and the summary; axe passes.
- Cancel, Retry and Remove appear by status and handler, are named with the file and report the id; non-retryable failures get no Retry.
- Announces done and failed uploads and the end of the batch; the total bar goes when nothing is active.
- Focus moves to the next row, then the heading, when rows are removed.
- Clear finished, indeterminate progress, decorative thumbnails, custom detail; no header with a named region; translated messages; server rendering.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/upload-queue; Cross-browser axe: /components/upload-queue |

Tests: `packages/react/src/components/files/upload-queue`

## All example code

### Mixed statuses

```tsx
import { useState } from 'react';
import { UploadQueue, type UploadQueueItem } from '@rookcom/monarch-react/collaboration';

const MB = 1024 * 1024;

const SAMPLE: UploadQueueItem[] = [
  { id: '1', name: 'quarterly-report.pdf', size: 2.4 * MB, status: 'done' },
  { id: '2', name: 'site-photo-01.jpg', size: 4.1 * MB, status: 'uploading', progress: 62 },
  { id: '3', name: 'site-photo-02.jpg', size: 3.8 * MB, status: 'queued' },
  {
    id: '4',
    name: 'floor-plan.dwg',
    size: 18 * MB,
    status: 'failed',
    error: 'Upload interrupted. Check your connection and try again.',
  },
  {
    id: '5',
    name: 'archive.zip',
    size: 120 * MB,
    status: 'failed',
    error: 'Larger than the 100 MB limit.',
    retryable: false,
  },
];

function QueueDemo() {
  const [items, setItems] = useState(SAMPLE);
  const set = (id: string, patch: Partial<UploadQueueItem>) =>
    setItems((l) => l.map((i) => (i.id === id ? { ...i, ...patch } : i)));
  return (
    <UploadQueue
      style={{ width: '100%', maxWidth: 520 }}
      items={items}
      onCancel={(id) => set(id, { status: 'cancelled' })}
      onRetry={(id) =>
        setItems((l) =>
          l.map((i) => {
            if (i.id !== id) return i;
            const { error: _error, ...rest } = i;
            return { ...rest, status: 'queued' };
          }),
        )
      }
      onRemove={(id) => setItems((l) => l.filter((i) => i.id !== id))}
      onClearFinished={() =>
        setItems((l) => l.filter((i) => i.status === 'uploading' || i.status === 'queued'))
      }
    />
  );
}

<QueueDemo />
```

### Without the header, with a custom step

```tsx
import { UploadQueue } from '@rookcom/monarch-react/collaboration';

const MB = 1024 * 1024;

<UploadQueue
  style={{ width: '100%', maxWidth: 520 }}
  showSummary={false}
  aria-label="Banner uploads"
  items={[
    {
      id: 'a',
      name: 'banner-wide.png',
      size: 1.2 * MB,
      status: 'done',
      detail: 'Checking for viruses',
    },
    { id: 'b', name: 'banner-square.png', size: 0.8 * MB, status: 'uploading' },
  ]}
/>
```
