import { AttachmentSample } from "@/components/docs/samples/attachment";
import * as AttachmentRadixSamples from "@/components/docs/samples/attachment.radix";
import { Flavored, FlavorSwitcher } from "@/components/docs/contexts/flavor.server";
import { PreviewCode } from "@/components/docs/preview-code.server";
import { AttachmentComposerSample } from "@/components/docs/samples/attachment/composer-attachments";
import * as AttachmentComposerRadixSample from "@/components/docs/samples/attachment/composer-attachments.radix";
import { AttachmentMessageContextSample } from "@/components/docs/samples/attachment/message-attachments";
import * as AttachmentMessageRadixSample from "@/components/docs/samples/attachment/message-attachments.radix";
import { AttachmentTypesSample } from "@/components/docs/samples/attachment/types";
import * as AttachmentTypesRadixSample from "@/components/docs/samples/attachment/types.radix";
import { AttachmentPreviewSample } from "@/components/docs/samples/attachment/image-preview";
import * as AttachmentPreviewRadixSample from "@/components/docs/samples/attachment/image-preview.radix";
<Flavored radix={<AttachmentRadixSamples.AttachmentSample />} base={} />
**Note:** These components provide the UI for attachments, but you also need to configure attachment adapters in your runtime to handle file uploads and processing. See the [Attachments Guide](/docs/guides/attachments) for complete setup instructions.Getting Started#
Add attachment#
<InstallCommand shadcn={["attachment"]} />
This adds a /components/assistant-ui/attachment.tsx file to your project, which you can adjust as needed.
Use in your application#
Add ComposerAttachments and ComposerAddAttachment to your composer:
import {
ComposerAttachments,
ComposerAddAttachment,
} from "@/components/assistant-ui/attachment";
const Composer: FC = () => {
return (
<ComposerPrimitive.Root className="...">
<ComposerAttachments />
<ComposerAddAttachment />
<ComposerPrimitive.Input
autoFocus
placeholder="Write a message..."
rows={1}
className="..."
/>
<ComposerAction />
</ComposerPrimitive.Root>
);
};
Add UserMessageAttachments to your user message:
import { UserMessageAttachments } from "@/components/assistant-ui/attachment";
const UserMessage: FC = () => {
return (
<MessagePrimitive.Root className="...">
<UserActionBar />
<UserMessageAttachments />
<div className="...">
<MessagePrimitive.Parts />
</div>
<BranchPicker className="..." />
</MessagePrimitive.Root>
);
};
Examples#
Composer#
In the composer, each attachment tile shows a remove button that deletes the attachment from the composer. Use the plus button to add your own files.
<PreviewCode file="components/docs/samples/attachment/composer-attachments" name="ComposerWithAttachments" base={}>
<AttachmentComposerRadixSample.AttachmentComposerSample />
User Message#
Message attachments are read-only. The same tile in a sent user message does not show a remove button.
<PreviewCode file="components/docs/samples/attachment/message-attachments" name="UserMessageWithAttachments" base={}>
<AttachmentMessageRadixSample.AttachmentMessageContextSample />
Custom Types#
This example shows the image tile and the generic fallback tile used for the built-in document type and the custom attachment type. The two fallback tiles use the same icon, but their accessible labels distinguish them.
<PreviewCode file="components/docs/samples/attachment/types" name="AttachmentTypesSample" base={}>
<AttachmentTypesRadixSample.AttachmentTypesSample />
Image Preview#
When you click an image tile or activate it with the keyboard, a full-size preview dialog opens.
<PreviewCode file="components/docs/samples/attachment/image-preview" name="AttachmentPreviewSample" base={}>
<AttachmentPreviewRadixSample.AttachmentPreviewSample />
API Reference#
Composer Attachments#
ComposerPrimitive.Attachments#
Renders all attachments in the composer.
<ParametersTable
type="ComposerPrimitiveAttachmentsProps"
parameters={[
{
name: "components",
type: "AttachmentComponents",
description: "Components to render for different attachment types.",
children: [
{
type: "AttachmentComponents",
parameters: [
{
name: "Image",
type: "ComponentType",
description: "Component for image attachments.",
},
{
name: "Document",
type: "ComponentType",
description: "Component for document attachments (PDF, etc.).",
},
{
name: "File",
type: "ComponentType",
description: "Component for generic file attachments.",
},
{
name: "Attachment",
type: "ComponentType",
description: "Fallback component for all attachment types.",
},
],
},
],
},
]}
/>
ComposerPrimitive.AddAttachment#
A button that opens the file picker to add attachments.
<ParametersTable
type="ComposerPrimitiveAddAttachmentProps"
parameters={[
{
name: "multiple",
type: "boolean",
default: "true",
description: "Allow selecting multiple files at once.",
},
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper button.",
},
]}
/>
This primitive renders a <button> element unless asChild is set.
Message Attachments#
MessagePrimitive.Attachments#
Renders all attachments in a user message.
<ParametersTable
type="MessagePrimitiveAttachmentsProps"
parameters={[
{
name: "components",
type: "AttachmentComponents",
description: "Components to render for different attachment types (same as ComposerPrimitive.Attachments).",
},
]}
/>
Attachment Primitives#
AttachmentPrimitive.Root#
Container for a single attachment.
<ParametersTable
type="AttachmentPrimitiveRootProps"
parameters={[
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper div.",
},
]}
/>
AttachmentPrimitive.Name#
Renders the attachment's file name.
AttachmentPrimitive.Remove#
A button to remove the attachment from the composer.
<ParametersTable
type="AttachmentPrimitiveRemoveProps"
parameters={[
{
name: "asChild",
type: "boolean",
default: "false",
description: "Merge props with child element instead of rendering a wrapper button.",
},
]}
/>
Attachment Types#
Attachments have the following structure:
type Attachment = {
id: string;
type: "image" | "document" | "file" | (string & {});
name: string;
contentType?: string;
file?: File;
status:
| { type: "running" | "requires-action" | "incomplete"; progress?: number }
| { type: "complete" };
};
The type field accepts custom strings (e.g. "data-workflow") beyond the built-in types. When an unknown type is encountered, the generic Attachment component is used as a fallback. The contentType field is optional — it can be omitted for non-file attachments where a MIME type is not meaningful.
Related Components#
- Thread - Main chat interface that displays attachments
- Attachments Guide - Complete setup instructions for attachment adapters