- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
- Typography
import { FileCodeIcon, XIcon } from "lucide-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 attachment
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
โโโ 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, 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
Examples#
Image#
Set variant="image" on AttachmentMedia and render an <img> inside it. Use orientation="vertical" to stack the media above the content.
import { XIcon } from "lucide-react"
import {States#
Set state to reflect the upload lifecycle. uploading and processing shimmer the title, and error switches to a destructive treatment.
import {
CheckIcon,
ClockIcon,Sizes#
Use size to switch between default, sm, and xs.
import { FileTextIcon } from "lucide-react"
import {Group#
Wrap attachments in AttachmentGroup to lay them out in a horizontally scrollable, snapping row with an edge fade.
import {
FileCodeIcon,
FileTextIcon,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.
import { CopyIcon, FileSearchIcon, XIcon } from "lucide-react"
import {<Dialog>
<Attachment>
{/* media, content, actions */}
<DialogTrigger asChild>
<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 asChild). 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 asChild>
<a
href={url}
target="_blank"
rel="noreferrer"
aria-label="Open workspace.png"
/>
</AttachmentTrigger>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.
| 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#
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#
Wraps the title and description.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional classes to apply to the content slot. |
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#
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#
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#
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#
A full-card overlay that activates the attachment. Renders a <button> by default.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render as the child element, such as a link. |
...props | React.ComponentProps<"button"> | - | Props spread to the trigger element. |
AttachmentGroup#
Lays out attachments in a horizontally scrollable, snapping row.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional classes to apply to the group. |
On This Page
InstallationUsageCompositionFeaturesExamplesImageStatesSizesGroupTriggerAccessibilityLabel icon-only actionsLabel the triggerKeyboard scrollingMeaning beyond colorAPI ReferenceAttachmentAttachmentMediaAttachmentContentAttachmentTitleAttachmentDescriptionAttachmentActionsAttachmentActionAttachmentTriggerAttachmentGroup