Attachment
Displays a file or image attachment with media, metadata, upload state, and actions.
Use Attachment for files and images in chat composers, message threads, and upload lists.
Installation
pnpm dlx cubix@latest add attachmentUsage
import {
Attachment,
AttachmentAction,
AttachmentActions,
AttachmentContent,
AttachmentDescription,
AttachmentMedia,
AttachmentTitle,
} from "@/components/cubix/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
└── AttachmentTriggerUse AttachmentGroup to lay out multiple attachments in a scrollable row:
AttachmentGroup
├── Attachment
└── AttachmentFeatures
- Icon and image media through AttachmentMedia
- Upload states: idle, uploading, processing, error, and done, with 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 className on every part
Examples
Image
Set variant="image" on AttachmentMedia and render an image inside it. Use orientation="vertical" to stack the media above the content.
States
Set state to reflect the upload lifecycle. uploading and processing shimmer the title, and error switches to a destructive treatment.
Sizes
Use size to switch between default, sm, and xs.
Group
Wrap attachments in AttachmentGroup to lay them out in a horizontally scrollable, snapping row with an edge fade.
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.
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={
<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
An AttachmentGroup scrolls horizontally. When its attachments are interactive, 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.
RTL
Wrap the attachment in dir="rtl" and lang="fa" so layout, actions, and IRANSans XV follow Persian.
API Reference
Attachment
The root attachment container.
| Prop | Type | Default | Description |
|---|---|---|---|
| state | "idle" | "uploading" | "processing" | "error" | "done" | "done" | Upload lifecycle. Drives border, color, and the title shimmer. |
| size | "default" | "sm" | "xs" | "default" | Attachment size. |
| orientation | "horizontal" | "vertical" | "horizontal" | Lay the media beside or above the content. |
| className | string | - | Additional Tailwind classes merged with the root styles (last one wins). |
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 image. |
| className | string | - | Additional Tailwind classes merged with the media styles (last one wins). |
AttachmentContent
Wraps the title and description.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional Tailwind classes merged with the component styles (last one wins). |
AttachmentTitle
The attachment name. Shimmers while the attachment is uploading or processing.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional Tailwind classes merged with the component styles (last one wins). |
AttachmentDescription
Secondary metadata such as the file type, size, or upload status.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional Tailwind classes merged with the component styles (last one wins). |
AttachmentActions
A container for one or more actions, aligned to the end of the attachment.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional Tailwind classes merged with the component styles (last one wins). |
AttachmentAction
An action button. Renders a Button and accepts all of its props.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | "ghost" | Visual style of the action button. |
| size | Button size | "icon-xs" | Size of the action button. |
| className | string | - | Additional Tailwind classes merged with the button styles (last one wins). |
AttachmentTrigger
A full-card overlay that activates the attachment. Renders a button by default.
| Prop | Type | Default | Description |
|---|---|---|---|
| render | React.ReactElement | - | Render the trigger as another element, such as a link. |
| ...props | React.ComponentProps<'button'> | - | Native button attributes, including aria-label. |
AttachmentGroup
Lays out attachments in a horizontally scrollable, snapping row.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional Tailwind classes merged with the component styles (last one wins). |