Components

Attachment

Displays a file or image attachment with media, metadata, upload state, and actions.

Source code

Click to see the source code for this component on GitHub. Feel free to copy it and adjust it for your own use.

Installation

Usage

The Attachment component displays a file or image attachment, its media, name, and metadata, with optional actions and upload state. Use it for files and images in chat composers, message threads, and upload lists.

Workspace
workspace.pngPNG · 820 KB
Desk
desk-reference.jpgJPG · 1.1 MB
Office
office-reference.jpgJPG · 940 KB
sales-dashboard.pdfUploading · 64%
message-renderer.vueTypeScript · 12 KB

Anatomy

vue

Attachment Anatomy.vue

<template>
  <UiAttachmentGroup>
    <UiAttachment>
      <UiAttachmentMedia />
      <UiAttachmentContent>
        <UiAttachmentTitle />
        <UiAttachmentDescription />
      </UiAttachmentContent>
      <UiAttachmentActions>
        <UiAttachmentAction />
      </UiAttachmentActions>
      <UiAttachmentTrigger />
    </UiAttachment>
  </UiAttachmentGroup>
</template>

Wrap multiple attachments in UiAttachmentGroup to lay them out in a scrollable, snapping row.

Features

  • Icon and image media through UiAttachmentMedia
  • Upload states: idle, uploading, processing, error, and done with built-in styling and a shimmer while in progress
  • Three sizes and horizontal or vertical orientation
  • A full-card UiAttachmentTrigger that opens a link or dialog while the actions stay independently clickable
  • Scrollable, snapping UiAttachmentGroup with an edge fade
  • Every part renders through Primitive, so as / as-child and Vue class overrides work on any part

Examples

Image

Set variant="image" on UiAttachmentMedia and render an <img> inside it. Use orientation="vertical" to stack the media above the content.

Workspace
workspace.pngPNG · 820 KB
Desk
desk-reference.jpgJPG · 1.1 MB
Office
office-reference.jpgJPG · 940 KB

States

Set state to reflect the upload lifecycle. uploading and processing shimmer the title, and error switches to a destructive treatment.

selected-file.pdfReady to upload
design-system.zipUploading · 64%
market-research.pdfProcessing document
financial-model.xlsx Upload failed. Try again.
uploaded-report.pdfUploaded · 1.8 MB

Sizes

Use size to switch between default, sm, and xs.

Default attachmentPDF · 2.4 MB
Small attachmentPDF · 2.4 MB
Extra small attachment

Group

Wrap attachments in UiAttachmentGroup to lay them out in a horizontally scrollable, snapping row with an edge fade.

briefing-notes.pdfPDF · 1.4 MB
workspace.png
workspace.pngPNG · 820 KB
customers.csvCSV · 18 KB
renderer.vueVue · 12 KB

Trigger

Add an UiAttachmentTrigger to make the whole card open a link or dialog. It fills the card behind the actions, so the actions stay clickable.

research-summary.pdfOpen preview dialog

Accessibility

UiAttachmentAction renders a Button, and UiAttachmentTrigger renders a real <button> (or your element via as-child). Follow the guidance below so both are operable and announced.

Label icon-only actions

UiAttachmentAction is usually icon-only, so give each one an aria-label describing the action and its target.

<template>
  <UiAttachmentAction aria-label="Remove sales-dashboard.pdf">
    <Icon name="lucide:x" />
  </UiAttachmentAction>
</template>

Label the trigger

UiAttachmentTrigger covers the card with no text of its own, so give it an aria-label for what activating it does.

<template>
  <UiAttachmentTrigger as-child>
    <a :href="url" target="_blank" rel="noreferrer" aria-label="Open workspace.png" />
  </UiAttachmentTrigger>
</template>

The trigger sits behind the actions in the stacking order, so an UiAttachmentAction and the UiAttachmentTrigger never trap each other — both remain separately focusable and clickable.

Keyboard scrolling

An UiAttachmentGroup scrolls horizontally. When its attachments are interactive: a trigger or actions, keyboard users reach off-screen items by tabbing to them. For a row of presentational attachments, make the group itself focusable and scrollable by adding tabindex="0", role="group", and an aria-label.

Meaning beyond color

The error state uses a destructive color. Keep the failure reason in UiAttachmentDescription so the state is not conveyed by color alone.

API Reference

Attachment

The root attachment container.

PropTypeDefaultDescription
state"idle" | "uploading" | "processing" | "error" | "done""done"The upload state. Drives styling and the shimmer.
size"default" | "sm" | "xs""default"The attachment size.
orientation"horizontal" | "vertical""horizontal"Lay the media beside or above the content.
asPrimitiveProps["as"]"div"Element or component to render.
as-childbooleanfalseRender as the child element.
classHTMLAttributes["class"]-Additional classes to apply to the root element.

AttachmentMedia

The media slot for an icon or image preview.

PropTypeDefaultDescription
variant"icon" | "image""icon"Whether the media holds an icon or an <img>.
classHTMLAttributes["class"]-Additional classes to apply to the media slot.

AttachmentContent

Wraps the title and description.

PropTypeDefaultDescription
classHTMLAttributes["class"]-Additional classes to apply to the content slot.

AttachmentTitle

The attachment name. Shimmers while the attachment is uploading or processing.

PropTypeDefaultDescription
classHTMLAttributes["class"]-Additional classes to apply to the title.

AttachmentDescription

Secondary metadata such as the file type, size, or upload status.

PropTypeDefaultDescription
classHTMLAttributes["class"]-Additional classes to apply to the description.

AttachmentActions

A container for one or more actions, aligned to the end of the attachment.

PropTypeDefaultDescription
classHTMLAttributes["class"]-Additional classes to apply to the actions.

AttachmentAction

An action button. Renders a Button and accepts Vue fallthrough attributes such as aria-label.

PropTypeDefaultDescription
variantButtonVariants["variant"]"ghost"The button variant.
sizeButtonVariants["size"]"icon-xs"The button size.
classHTMLAttributes["class"]-Additional classes to apply to the action.

AttachmentTrigger

A full-card overlay that activates the attachment. Renders a <button> by default and accepts Vue fallthrough attributes such as aria-label.

PropTypeDefaultDescription
asPrimitiveProps["as"]"button"Element or component to render.
as-childbooleanfalseRender as the child element, such as a link.
classHTMLAttributes["class"]-Additional classes to apply to the trigger.

AttachmentGroup

Lays out attachments in a horizontally scrollable, snapping row.

PropTypeDefaultDescription
classHTMLAttributes["class"]-Additional classes to apply to the group.