HomeDocsComponentsBlocksChartsThemes
Introduction
  • Introduction
  • Installation
  • Themes
  • llms.txt
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Amount
  • Aspect Ratio
  • Audio Player
  • Avatar
  • Avatar Upload
  • Badge
  • Banner
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Code Block
  • Collapsible
  • Color Picker
  • Combobox
  • Command
  • Context Menu
  • Copy Button
  • Countdown
  • Data Grid
  • Data Table
  • Date Picker
  • Date Range Picker
  • Description List
  • Device Mockup
  • Dialog
  • Direction
  • Dot Loader
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • File Upload
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kanban
  • Kbd
  • Label
  • Meter
  • Multi Select
  • Native Select
  • Number Field
  • Pagination
  • Password Strength
  • Phone Input
  • Popover
  • Progress
  • Progress Circle
  • Radio Group
  • Rating
  • Resizable
  • Responsive Dialog
  • Rich Text Editor
  • Scroll Area
  • Segmented Control
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Signature
  • Skeleton
  • Slider
  • Sonner
  • Sortable
  • Spinner
  • Stat
  • Stepper
  • Switch
  • Table
  • Tabs
  • Tag Input
  • Terminal
  • Textarea
  • Time Field
  • Timeline
  • Toast
  • Toggle
  • Toggle Group
  • Tooltip
  • Tree
  • Typography
  • Video Player
  • Window Mockup
AI
  • Message Scroller
  • Message
  • Bubble
  • Marker
  • Attachment
  • Questionnaire
  • Composer
  • Reasoning
  • Tool Call
  • Approval Card
  • Citations
Blocks
  • Airtable
  • Airtable Kanban
  • ClickUp List
  • ClickUp Kanban
  • Repeatable Group
  • Command Palette
  • Sign In and Sign Up
  • Availability Scheduler
  • AI Chat
  • Action Bar
  • Notion
  • Banking
  • Lineup Builder
  • Sports Score
  • Strava
  • Sheets
  • Notices
  • Settings
  • Billing
Utilities
  • motion
  • sounds
  • scroll-fade
  • shimmer
Another UI. Built on shadcn/ui with Phosphor icons.

Attachment

PreviousNext

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

Base UIReact AriaRadix UI
Workspace
workspace.pngPNG · 820 KB
Desk
desk-reference.jpgJPG · 1.1 MB
Office
office-reference.jpgJPG · 940 KB
sales-dashboard.pdfUploading · 64%
message-renderer.tsxTypeScript · 12 KB
import { CodeIcon, XIcon } from "@phosphor-icons/react"

import {

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.

Installation#

pnpm dlx shadcn@latest add https://anotherui.dev/r/attachment.json

Usage#

import {
  Attachment,
  AttachmentAction,
  AttachmentActions,
  AttachmentContent,
  AttachmentDescription,
  AttachmentMedia,
  AttachmentTitle,
} from "@/components/ui/attachment"
<Attachment>
  <AttachmentMedia>
    <FileTextIcon />
  </AttachmentMedia>
  <AttachmentContent>
    <AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
    <AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
  </AttachmentContent>
  <AttachmentActions>
    <AttachmentAction aria-label="Remove sales-dashboard.pdf">
      <XIcon />
    </AttachmentAction>
  </AttachmentActions>
</Attachment>

Composition#

Use the following composition to build an attachment:

Attachment
├── AttachmentMedia
├── AttachmentContent
│   ├── AttachmentTitle
│   └── AttachmentDescription
├── AttachmentActions
│   └── AttachmentAction
└── AttachmentTrigger

Use AttachmentGroup to lay out multiple attachments in a scrollable row:

AttachmentGroup
├── Attachment
└── Attachment

Features#

  • Icon and image media through AttachmentMedia
  • 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 AttachmentTrigger that opens a link or dialog while the actions stay independently clickable
  • Scrollable, snapping AttachmentGroup with an edge fade
  • Customizable styling through the className prop on every part

Image#

Set variant="image" on AttachmentMedia 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
import { XIcon } from "@phosphor-icons/react"

import {

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.xlsxUpload failed. Try again.
uploaded-report.pdfUploaded · 1.8 MB
import { ArrowClockwiseIcon, CheckIcon, ClockIcon, FileTextIcon, FileXIcon, XIcon } from "@phosphor-icons/react"

import {

Sizes#

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

Default attachmentPDF · 2.4 MB
Small attachmentPDF · 2.4 MB
Extra small attachment
import { FileTextIcon } from "@phosphor-icons/react"

import {

Group#

Wrap attachments in AttachmentGroup 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.tsxTSX · 12 KB
import { CodeIcon, FileTextIcon, TableIcon, XIcon } from "@phosphor-icons/react"
import type { Icon as PhosphorIcon } from "@phosphor-icons/react"

Trigger#

Add an AttachmentTrigger 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
import { CopyIcon, FileMagnifyingGlassIcon, XIcon } from "@phosphor-icons/react"

import {
<Dialog>
  <Attachment>
    {/* media, content, actions */}
    <DialogTrigger>
      <AttachmentTrigger aria-label="Preview research-summary.pdf" />
    </DialogTrigger>
  </Attachment>
  <DialogContent>{/* ... */}</DialogContent>
</Dialog>

Accessibility#

AttachmentAction renders a Button, and AttachmentTrigger renders a real <button> (or your element via render). Follow the guidance below so both are operable and announced.

Label icon-only actions#

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

<AttachmentAction aria-label="Remove sales-dashboard.pdf">
  <XIcon />
</AttachmentAction>

Label the trigger#

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

<AttachmentTrigger
  render={(props) => (
    <a
      {...props}
      href={url}
      target="_blank"
      rel="noreferrer"
      aria-label="Open workspace.png"
    />
  )}
/>

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

Keyboard scrolling#

An AttachmentGroup 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 AttachmentDescription 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.
classNamestring-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>.
classNamestring-Additional classes to apply to the media slot.

AttachmentContent#

Wraps the title and description.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the content slot.

AttachmentTitle#

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

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the title.

AttachmentDescription#

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

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the description.

AttachmentActions#

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

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the actions.

AttachmentAction#

An action button. Renders a Button and accepts all of its props.

PropTypeDefaultDescription
sizeButton["size"]"icon-xs"The button size.
...propsReact.ComponentProps<typeof Button>-Props spread to the underlying Button.

AttachmentTrigger#

A full-card overlay that activates the attachment. Renders a <button> by default.

PropTypeDefaultDescription
renderReactElement | function-Render as a different element, such as a link.
...propsReact.ComponentProps<"button">-Props spread to the trigger element.

AttachmentGroup#

Lays out attachments in a horizontally scrollable, snapping row.

PropTypeDefaultDescription
classNamestring-Additional classes to apply to the group.
Aspect RatioAudio Player

On This Page

InstallationUsageCompositionFeaturesImageStatesSizesGroupTriggerAccessibilityLabel icon-only actionsLabel the triggerKeyboard scrollingMeaning beyond colorAPI ReferenceAttachmentAttachmentMediaAttachmentContentAttachmentTitleAttachmentDescriptionAttachmentActionsAttachmentActionAttachmentTriggerAttachmentGroup