Attachment
A file or image attachment with media, metadata, upload state, and actions.
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.
Usage
import {
Attachment,
AttachmentAction,
AttachmentActions,
AttachmentContent,
AttachmentDescription,
AttachmentMedia,
AttachmentTitle,
} from '@epilot/spark-ui/attachment'<Attachment>
<AttachmentMedia>
<MaterialSymbol name="content_copy" />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>feed-in-report.pdf</AttachmentTitle>
<AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
</AttachmentContent>
<AttachmentActions>
<AttachmentAction aria-label="Remove feed-in-report.pdf">
<MaterialSymbol name="close" />
</AttachmentAction>
</AttachmentActions>
</Attachment>Composition
Attachment
├── AttachmentMedia
├── AttachmentContent
│ ├── AttachmentTitle
│ └── AttachmentDescription
├── AttachmentActions
│ └── AttachmentAction
└── AttachmentTriggerUse AttachmentGroup to lay out multiple attachments in a scrollable row.
Examples
Image
Set variant="image" on AttachmentMedia and render an <img> 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. Pass render
to swap in a link or a dialog trigger.
<Attachment>
{/* media, content, actions */}
<AttachmentTrigger
render={
<a
href={url}
target="_blank"
rel="noreferrer"
aria-label="Open workspace.png"
/>
}
/>
</Attachment>Accessibility
- Label icon-only actions.
AttachmentActionis usually icon-only, so give each one anaria-labeldescribing the action and its target. - Label the trigger.
AttachmentTriggercovers the card with no text of its own, so give it anaria-labelfor what activating it does. It sits behind the actions in the stacking order, so both stay separately focusable. - Meaning beyond color. The
errorstate uses a destructive color; keep the failure reason inAttachmentDescription.
API Reference
Attachment
| 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. |
AttachmentMedia
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'icon' | 'image' | 'icon' | Whether the media holds an icon or an <img>. |
className | string | — | Additional classes. |
AttachmentAction
Renders a Spark Button and accepts all of its
props. Defaults to styleVariant="ghost", color="neutral", size="icon-small".
AttachmentTrigger
A full-card overlay that activates the attachment. Renders a <button> by
default; pass render to render a link or a dialog trigger.
AttachmentContent / AttachmentTitle / AttachmentDescription / AttachmentActions / AttachmentGroup
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional classes to apply to the part. |
AttachmentTitle shimmers while the attachment is uploading or processing.
AttachmentGroup lays attachments out in a horizontally scrollable, snapping
row with an edge fade.