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
Section titled “Installation”pnpm dlx shadcn@latest add pxl-ui/registry/attachment
Install the following dependencies:
pnpm add @base-ui/react
Copy and paste the following code into your project.
Update the import paths to match your project setup.
import { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentMedia, AttachmentTitle,} from "@/components/ui/pxl/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
Section titled “Composition”Use the following composition to build an attachment:
Attachment├── AttachmentMedia├── AttachmentContent│ ├── AttachmentTitle│ └── AttachmentDescription├── AttachmentActions│ └── AttachmentAction└── AttachmentTriggerUse AttachmentGroup to lay out multiple attachments in a scrollable row:
AttachmentGroup├── Attachment└── AttachmentFeatures
Section titled “Features”- Icon and image media through
AttachmentMedia - Upload states:
idle,uploading,processing,error, anddonewith built-in styling and a shimmer while in progress - Three sizes and horizontal or vertical orientation
- A full-card
AttachmentTriggerthat opens a link or dialog while the actions stay independently clickable - Scrollable, snapping
AttachmentGroupwith an edge fade - Customizable styling through the
classNameprop on every part
Set variant="image" on AttachmentMedia and render an <img> inside it. Use orientation="vertical" to stack the media above the content.
States
Section titled “States”Set state to reflect the upload lifecycle. uploading and processing shimmer the title, and error switches to a destructive treatment.
Use size to switch between default, sm, and xs.
Wrap attachments in AttachmentGroup to lay them out in a horizontally scrollable, snapping row with an edge fade.
Trigger
Section titled “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.
<Dialog> <Attachment> {/* media, content, actions */} <DialogTrigger render={<AttachmentTrigger aria-label="Preview research-summary.pdf" />} /> </Attachment> <DialogContent>{/* ... */}</DialogContent></Dialog>Accessibility
Section titled “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
Section titled “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
Section titled “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={ <a 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
Section titled “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
Section titled “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
Section titled “API Reference”Attachment
Section titled “Attachment”The root attachment container.
| Prop | Type | Default | Description |
|---|---|---|---|
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. |
className |
string |
- | Additional classes to apply to the root element. |
AttachmentMedia
Section titled “AttachmentMedia”The media slot for an icon or image preview.
| Prop | Type | Default | Description |
|---|---|---|---|
variant |
"icon" | "image" |
"icon" |
Whether the media holds an icon or an <img>. |
className |
string |
- | Additional classes to apply to the media slot. |
AttachmentContent
Section titled “AttachmentContent”Wraps the title and description.
| Prop | Type | Default | Description |
|---|---|---|---|
className |
string |
- | Additional classes to apply to the content slot. |
AttachmentTitle
Section titled “AttachmentTitle”The attachment name. Shimmers while the attachment is uploading or processing.
| Prop | Type | Default | Description |
|---|---|---|---|
className |
string |
- | Additional classes to apply to the title. |
AttachmentDescription
Section titled “AttachmentDescription”Secondary metadata such as the file type, size, or upload status.
| Prop | Type | Default | Description |
|---|---|---|---|
className |
string |
- | Additional classes to apply to the description. |
AttachmentActions
Section titled “AttachmentActions”A container for one or more actions, aligned to the end of the attachment.
| Prop | Type | Default | Description |
|---|---|---|---|
className |
string |
- | Additional classes to apply to the actions. |
AttachmentAction
Section titled “AttachmentAction”An action button. Renders a Button and accepts all of its props.
| Prop | Type | Default | Description |
|---|---|---|---|
size |
Button["size"] |
"icon-xs" |
The button size. |
...props |
React.ComponentProps<typeof Button> |
- | Props spread to the underlying Button. |
AttachmentTrigger
Section titled “AttachmentTrigger”A full-card overlay that activates the attachment. Renders a <button> by default.
| Prop | Type | Default | Description |
|---|---|---|---|
render |
ReactElement | function |
- | Render as a different element, such as a link. |
...props |
React.ComponentProps<"button"> |
- | Props spread to the trigger element. |
AttachmentGroup
Section titled “AttachmentGroup”Lays out attachments in a horizontally scrollable, snapping row.
| Prop | Type | Default | Description |
|---|---|---|---|
className |
string |
- | Additional classes to apply to the group. |