# Attachment
URL: /docs/primitives/attachment
File and image attachment rendering for the composer and messages.
The Attachment primitive renders file and image attachments. It appears in two places: inside the composer for pending uploads (with a remove button), and inside messages for sent attachments (read-only). You provide the layout and styling.
```tsx
import {
AttachmentPrimitive,
ComposerPrimitive,
} from "@assistant-ui/react";
import { XIcon } from "lucide-react";
function ComposerAttachment() {
return (
);
}
```
Quick Start \[#quick-start]
An attachment inside a composer:
```tsx
import { AttachmentPrimitive, ComposerPrimitive } from "@assistant-ui/react";
{() => }
Send
```
`Root` renders a `
`, `unstable_Thumb` renders a `
` showing the file extension with a leading dot (e.g., `.pdf`), `Name` renders plain text, and `Remove` renders a `
`.
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
Core Concepts \[#core-concepts]
Two Contexts \[#two-contexts]
Attachments appear in two different contexts:
* **Composer**: via `ComposerPrimitive.Attachments`. These are pending uploads that can be removed before sending.
* **Messages**: via `MessagePrimitive.Attachments`. These are sent attachments, displayed read-only (the iterator renders attachments for user messages).
The same `AttachmentPrimitive` parts work in both contexts. The difference is behavioral: `Remove` only works in the composer context.
Iterator Pattern \[#iterator-pattern]
You don't loop over attachments yourself. Instead, use the children render function:
```tsx
// Composer attachments
{({ attachment }) => {
if (attachment.type === "image") return ;
if (attachment.type === "document") return ;
return ;
}}
// Message attachments
{({ attachment }) => {
if (attachment.type === "image") return ;
if (attachment.type === "document") return ;
return ;
}}
```
Each component receives its attachment context automatically, with no props to pass. `components` is deprecated — use the `children` render function instead.
Remove Button \[#remove-button]
`Remove` calls the attachment runtime remove action. In composer attachments it removes the attachment from the pending message. In message attachments, this action is not supported and clicking `Remove` will throw `"Message attachments cannot be removed"`. Only render `Remove` in composer UIs.
Name as Text \[#name-as-text]
`Name` renders plain text with no wrapper element. Wrap it in a `` or other element for styling:
```tsx
```
Parts \[#parts]
Root \[#root]
Container for a single attachment item. Renders a `` element unless `asChild` is set.
```tsx
```
unstable\_Thumb \[#unstable\_thumb]
Thumbnail slot for attachment previews. Renders a `
` element unless `asChild` is set.
```tsx
```
Name \[#name]
Renders the attachment filename text.
```tsx
```
Remove \[#remove]
Button that removes the current attachment when used in a removable attachment context. Renders a `
` element unless `asChild` is set.
```tsx
```
Patterns \[#patterns]
Composer Attachment with Remove \[#composer-attachment-with-remove]
```tsx
function ComposerAttachmentItem() {
return (
);
}
Send
```
Message Attachment (Read-Only) \[#message-attachment-read-only]
```tsx
function MessageAttachment() {
return (
);
}
```
Custom Layout with asChild \[#custom-layout-with-aschild]
```tsx
```
Relationship to Components \[#relationship-to-components]
The shadcn [Attachment](/docs/ui/attachment) component wraps these primitives with styled thumbnails, tooltip filenames, remove buttons, and image preview dialogs. Start there for a prebuilt attachment UI.
API Reference \[#api-reference]
For full prop details on every part, see the [AttachmentPrimitive API Reference](/docs/api-reference/primitives/attachment).
Related:
* [ComposerPrimitive API Reference](/docs/api-reference/primitives/composer)
* [MessagePrimitive API Reference](/docs/api-reference/primitives/message)