Primitives for the text input, send button, and attachments.
The user interface to add new messages or edit existing ones.
Dual Use! A Composer placed directly inside a Thread will compose new
messages. A Composer placed inside a Message will edit that message.
Anatomy
import { ComposerPrimitive } from "@assistant-ui/react";
// creating a new message
const Composer = () => (
<ComposerPrimitive.Root>
<ComposerPrimitive.Quote>
<ComposerPrimitive.QuoteText />
<ComposerPrimitive.QuoteDismiss />
</ComposerPrimitive.Quote>
<ComposerPrimitive.Attachments />
<ComposerPrimitive.AddAttachment />
<ComposerPrimitive.Input />
<ComposerPrimitive.Send />
</ComposerPrimitive.Root>
);
// editing an existing message
const EditComposer = () => (
<ComposerPrimitive.Root>
<ComposerPrimitive.Input />
<ComposerPrimitive.Send />
<ComposerPrimitive.Cancel />
</ComposerPrimitive.Root>
);
// with voice input (dictation)
const ComposerWithDictation = () => (
<ComposerPrimitive.Root>
<ComposerPrimitive.Input />
<ComposerPrimitive.If dictation={false}>
<ComposerPrimitive.Dictate />
</ComposerPrimitive.If>
<ComposerPrimitive.If dictation>
<ComposerPrimitive.StopDictation />
</ComposerPrimitive.If>
<ComposerPrimitive.Send />
</ComposerPrimitive.Root>
);API Reference
Root
Containts all parts of the composer.
This primitive renders a <form> element unless asChild is set.
ComposerRootPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
Input
The text input field for the user to type a new message.
This primitive renders a <textarea> element unless asChild is set.
ComposerPrimitiveInputPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
submitMode: "enter" | "ctrlEnter" | "none"= "enter"Controls how the Enter key submits messages. "enter": plain Enter submits (Shift+Enter for newline). "ctrlEnter": Ctrl/Cmd+Enter submits (plain Enter for newline). "none": keyboard submission disabled.
Keyboard Shortcuts
Default (submitMode="enter"):
| Key | Description |
|---|---|
| Enter | Sends the message. |
| Shift + Enter | Inserts a newline. |
| Escape | Sends a cancel action. |
With submitMode="ctrlEnter":
| Key | Description |
|---|---|
| Ctrl/Cmd + Enter | Sends the message. |
| Enter | Inserts a newline. |
| Escape | Sends a cancel action. |
Send
The button to send the message.
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveSendPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
multiple: boolean | undefined= trueAllow selecting multiple attachments at the same time.
Cancel
Sends a cancel action.
In edit composers, this action exits the edit mode. In thread composers, this action stops the current run.
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveCancelPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
Attachments
Renders attachments. This primitive renders a separate component for each attachment.
ComposerPrimitiveAttachmentsPropscomponents?: ComposerAttachmentsComponentsThe component to render for each attachment.
ComposerPrimitiveAttachmentsProps['components']Image?: ComponentTypeThe component to render for each image attachment.
Document?: ComponentTypeThe component to render for each document attachment.
File?: ComponentTypeThe component to render for each file attachment.
Fallback?: ComponentTypeThe component to render for each attachment type.
AttachmentByIndex
Renders a single attachment at the specified index within the composer.
<ComposerPrimitive.AttachmentByIndex
index={0}
components={{
Image: MyImageAttachment,
Document: MyDocumentAttachment
}}
/>ComposerPrimitive.AttachmentByIndex.Propsindexrequired: numberThe index of the attachment to render.
components?: ComposerAttachmentsComponentsThe components to render for the attachment.
AddAttachment
Renders a button to add an attachment.
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveAddAttachmentPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
Dictate
Renders a button to start dictation to convert voice to text.
Requires a DictationAdapter to be configured in the runtime.
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveDictatePropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
StopDictation
Renders a button to stop the current dictation session.
Only rendered when dictation is active.
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveStopDictationPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
DictationTranscript
Renders the current interim (partial) transcript while dictation is active.
Note: By default, interim transcripts are displayed directly in the composer input (like native dictation). This component is for advanced customization when you want to display the interim transcript separately (e.g., in a different style or location).
Only renders when there is an active interim transcript (returns null otherwise).
This primitive renders a <span> element.
{/* Optional: Display interim transcript separately with custom styling */}
<ComposerPrimitive.If dictation>
<div className="dictation-preview">
<ComposerPrimitive.DictationTranscript className="italic text-muted" />
</div>
</ComposerPrimitive.If>Quote
A container for displaying a quote preview in the composer. Only renders when a quote is set via composer.setQuote().
This primitive renders a <div> element.
<ComposerPrimitive.Quote className="flex items-start gap-2 bg-muted/60 px-3 py-2">
<ComposerPrimitive.QuoteText className="line-clamp-2 flex-1 text-sm" />
<ComposerPrimitive.QuoteDismiss>×</ComposerPrimitive.QuoteDismiss>
</ComposerPrimitive.Quote>QuoteText
Renders the quoted text content. Only renders when a quote is set.
This primitive renders a <span> element.
QuoteDismiss
A button that clears the current quote from the composer by calling setQuote(undefined).
This primitive renders a <button> element unless asChild is set.
ComposerPrimitiveQuoteDismissPropsasChild: boolean= falseChange the default rendered element for the one passed as a child, merging their props and behavior.
Read the Composition guide for more details.
See the Quoting guide for a complete walkthrough including the floating selection toolbar and backend handling.
If
Renders children if a condition is met.
UseComposerIfPropsediting?: boolean | undefinedRender children if the message is being edited.
dictation?: boolean | undefinedRender children if dictation is active.
<Composer.If editing>{/* rendered if message is being edited */}</Composer.If>
<Composer.If dictation>{/* rendered if dictation is active */}</Composer.If>