---
title: Attachment Tray
description: A tray that displays a message's image and file attachments.
category: AiChat
status: beta
since: 0.3.9
tags: [ai, attachment, upload]
syncStatus: reviewed
verified: true
---

## Usage

### Basic
::::TuffDemoWrapper{demo="AttachmentTrayAttachmentTrayDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  const attachments = [
    { kind: 'image', id: 'i1', url: 'https://picsum.photos/id/1015/400/300', name: 'canyon.jpg' },
    { kind: 'file', id: 'f1', name: 'report.pdf', size: 240_000 },
    { kind: 'file', id: 'f2', name: 'uploading.zip', size: 1_200_000, uploading: true, progress: 0.4 },
  ]
  </script>

  <template>
    <TxAttachmentTray
      :attachments="attachments"
      removable
      @remove="onRemove"
      @cancel="onCancel"
      @open="onOpen"
    />
  </template>
---
::::

### Best Practices

- Set `removable` in a composer; leave it off on sent messages so they stay read-only.
- Handle `remove` and `cancel` by dropping that `id` from your list; the component never mutates `attachments`.
- Give an in-flight attachment both `uploading: true` and `progress` (0–1); without `progress`, no progress shows.
- Handle `open`; otherwise clicking a file chip does nothing.
- On non-English surfaces, override every text prop and `sizeFormatter`; `previousText` and `nextText` are visible text.

## API Reference

### TxAttachmentTray

#### Props

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `attachments` | `AiAttachment[]` | — | Images and files in one list. Required. |
| `removable` | `boolean` | `false` | Shows remove buttons; cancel-upload buttons don't depend on it. |
| `previewTitle` | `string` | `'Preview'` | Viewer title when the image has no `name`. |
| `previousLabel` | `string` | `'Previous image'` | Accessible name of the previous button. |
| `nextLabel` | `string` | `'Next image'` | Accessible name of the next button. |
| `previousText` | `string` | `'Prev'` | Visible text of the previous button. |
| `nextText` | `string` | `'Next'` | Visible text of the next button. |
| `removeLabel` | `string` | `'Remove attachment'` | Accessible name of remove buttons. |
| `cancelLabel` | `string` | `'Cancel upload'` | Accessible name of cancel-upload buttons. |
| `sizeFormatter` | `(bytes: number) => string` | — | Formats file sizes; defaults to B/KB/MB with one decimal. |

#### Events

| Name | Payload | Description |
|------|---------|-------------|
| `remove` | `(id: string)` | Fires when remove is clicked. |
| `cancel` | `(id: string)` | Fires when cancel-upload is clicked. |
| `open` | `(attachment: AiAttachmentFile)` | Fires when a file chip is clicked; images open the built-in viewer. |

### TxAttachmentChip

#### Props

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `attachment` | `AiAttachment & { kind: 'file' }` | — | The file attachment to show. Required. |
| `removable` | `boolean` | `false` | Shows the remove button; the cancel-upload button doesn't depend on it. |
| `removeLabel` | `string` | `'Remove attachment'` | Accessible name of the remove button. |
| `cancelLabel` | `string` | `'Cancel upload'` | Accessible name of the cancel-upload button. |
| `sizeFormatter` | `(bytes: number) => string` | — | Formats the file size; defaults to the same format as `TxAttachmentTray`. |

#### Events

| Name | Payload | Description |
|------|---------|-------------|
| `remove` | `(id: string)` | Fires when remove is clicked. |
| `cancel` | `(id: string)` | Fires when cancel-upload is clicked. |
| `open` | `(attachment: AiAttachment & { kind: 'file' })` | Fires when the chip body is clicked. |

## Overview

- `kind: 'image'` items go to the image grid and `kind: 'file'` items to file chips; pass both in one `attachments` array.
- Each file renders as a `TxAttachmentChip`; the tray forwards `removable`, `removeLabel`, `cancelLabel`, and `sizeFormatter` to it.
- Clicking an image opens the built-in viewer (on `TxModal`), which pages through images only and emits nothing.
- An `uploading` attachment always shows a cancel button: images draw a progress ring, file chips show a percentage.
- A thumbnail that fails to load becomes a placeholder and is not retried.
