Skip to content

Chat Composer

Chat input shell: manages the message value, wires the default input and send button through context, and lays out header, footer, and status slots around them.

<div className={containerStyle}>
<ChatComposer {...args} />
</div>
32k tokens left
<div className={containerStyle}>
<ChatComposer
{...args}
footerActions={
<Button
icon={SlidersHorizontal}
isIconOnly
label="Options"
variant="ghost"
/>
}
headerActions={
<Button
icon={Paperclip}
isIconOnly
label="Attach"
size="sm"
variant="ghost"
/>
}
headerContext={<Text size="sm">32k tokens left</Text>}
sendActions={
<Button icon={Mic} isIconOnly label="Dictate" variant="ghost" />
}
/>
</div>
function StopModeDemo() {
const [isStopShown, setIsStopShown] = useState(true);
return (
<div className={containerStyle}>
<ChatComposer
isStopShown={isStopShown}
onStop={() => setIsStopShown(false)}
onSubmit={() => setIsStopShown(true)}
placeholder="Submit to stream, stop to cancel…"
/>
</div>
);
}
<StopModeDemo />
<div className={containerStyle}>
<ChatComposer
{...args}
status={{message: 'Message failed to send. Retry?', type: 'error'}}
/>
</div>
The context window is almost full.
<div className={containerStyle}>
<ChatComposer
{...args}
status={{
message: 'The context window is almost full.',
type: 'warning',
}}
statusPosition="top"
/>
</div>
Draft: (empty) — sent: (none)
function ControlledDemo() {
const [value, setValue] = useState('');
const [sent, setSent] = useState<string[]>([]);
return (
<div className={containerStyle}>
<ChatComposer
onChange={setValue}
onSubmit={next => setSent(current => [...current, next])}
value={value}
/>
<Text size="sm">
Draft: {value === '' ? '(empty)' : value} — sent:{' '}
{sent.length === 0 ? '(none)' : sent.join(', ')}
</Text>
</div>
);
}
<ControlledDemo />
<div className={containerStyle}>
<ChatComposer {...args} />
</div>

Chat input shell: manages the message value, wires the default input and send button through context, and lays out header, footer, and status slots around them.

PropTypeDefaultDescription
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
density"compact" | "balanced" | "spacious"'balanced'Density preset controlling body padding and gaps. Defaults to the surrounding ChatLayout density.
footerActionsReactNode—Actions rendered at the start of the footer row.
headerActionsReactNode—Actions rendered at the start of the header row (e.g. attach buttons).
headerContextReactNode—Contextual info rendered at the end of the header row.
inputReactNode—Custom input element that replaces the default ChatComposerInput.
isDisabledbooleanfalseWhether the composer is disabled.
isStopShownbooleanfalseWhether the stop button is shown instead of the send button. Use while a response is streaming.
onChange(value: string) => void—Called when the input value changes.
onStop() => void—Called when the user clicks the stop button.
onSubmit*(value: string) => void—Called with the trimmed input value when the user submits. The input is cleared afterwards when uncontrolled.
placeholderstring'Type a message…'Placeholder text for the input.
refRef<HTMLDivElement>—Ref forwarded to the root element.
sendActionsReactNode—Actions rendered directly before the send button.
sendButtonReactNode—Custom send button that replaces the default ChatSendButton.
statusChatComposerStatus—Status message rendered attached to the composer body.
statusPosition'bottom' | 'top''bottom'Which edge of the composer the status attaches to.
styleCSSProperties—Inline styles applied to the root element.
valuestring—Controlled input value. When set, the parent owns the value and should clear it in onSubmit.
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.

Auto-growing textarea for the chat composer. Enter submits, Shift+Enter inserts a newline, and the input grows with its content up to `maxRows` lines. Reads value, submit, and placeholder wiring from the surrounding ChatComposer, so it works with no props inside one.

PropTypeDefaultDescription
autoCompletestring—HTML autocomplete attribute for the textarea.
classNamestring—Additional CSS class names applied to the textarea.
data-testidstring—Test ID applied to the textarea.
enterKeyHintTextareaHTMLAttributes<HTMLTextAreaElement>['enterKeyHint']—Action label shown on the virtual keyboard's enter key.
isDisabledbooleanfalseWhether the input is disabled. Defaults to the surrounding ChatComposer state.
maxLengthnumber—Maximum number of characters the user can type.
maxRowsnumber8Maximum number of lines the input grows to before scrolling.
minRowsnumber1Minimum number of lines the input occupies.
namestring—HTML name attribute for form submission.
onBlurFocusEventHandler<HTMLTextAreaElement>—Blur event handler for the textarea.
onChange(value: string) => void—Called when the value changes. Defaults to the surrounding ChatComposer state.
onFocusFocusEventHandler<HTMLTextAreaElement>—Focus event handler for the textarea.
onKeyDownKeyboardEventHandler<HTMLTextAreaElement>—Keyboard event handler for the textarea, called before the built-in Enter-to-submit handling. Call preventDefault() to suppress it.
onPasteClipboardEventHandler<HTMLTextAreaElement>—Paste event handler for the textarea — use to intercept pasted files or rich content.
onSubmit() => void—Called with the trimmed value when the user presses Enter. Defaults to submitting the surrounding ChatComposer.
placeholderstring'Type a message…'Placeholder text. Defaults to the surrounding ChatComposer placeholder.
refRef<HTMLTextAreaElement>—Ref forwarded to the textarea element.
styleCSSProperties—Inline styles applied to the textarea.
valuestring—Controlled value. Defaults to the surrounding ChatComposer value.
aria-describedbyAriaAttributes['aria-describedby']—Identifies the element(s) that describe the region.
aria-labelAriaAttributes['aria-label']—Accessible label for the region.
aria-labelledbyAriaAttributes['aria-labelledby']—Identifies the element(s) that label the region.
idstring—HTML id attribute applied to the root element.

Circular send/stop toggle button for the chat composer. Reads state from the surrounding ChatComposer by default; every value can be overridden via props for standalone usage.

PropTypeDefaultDescription
classNamestring—Additional CSS class names applied to the button.
data-testidstring—Test ID applied to the button.
isDisabledboolean—Whether the send button is disabled. Defaults to !canSend from the surrounding ChatComposer.
isStopShownbooleanfalseWhether the stop button is shown instead of the send button. Defaults to the surrounding ChatComposer state.
onSend() => void—Called when the user clicks the send button. Defaults to submitting the surrounding ChatComposer.
onStop() => void—Called when the user clicks the stop button. Defaults to the surrounding ChatComposer onStop.
refRef<HTMLElement>—Ref forwarded to the button element.
sendIconIconComponentArrowUpIcon for the send state.
size'md' | 'sm''md'Button size.
stopIconIconComponentSquareIcon for the stop state.
styleCSSProperties—Inline styles applied to the button.
formstring—HTML form attribute associating the button with a <form> by ID.
idstring—HTML id attribute applied to the root element.
aria-controlsstring—Identifies the element(s) whose contents are controlled by the button.
aria-describedbystring—Identifies the element(s) that describe the button.
aria-detailsstring—Identifies the element that provides a detailed description.
aria-expandedboolean—Indicates whether a controlled element is expanded or collapsed.
aria-haspopupboolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'—Indicates the button opens an interactive popup element.
aria-keyshortcutsstring—Keyboard shortcuts that activate or focus the button.
aria-labelledbystring—Identifies the element(s) that label the button.
onFocusFocusEventHandler<HTMLElement>—Focus event handler for the root element.
onKeyDown(event: KeyboardEvent<HTMLElement>) => void—Keyboard event handler for the root element.
onPointerEnterPointerEventHandler<HTMLElement>—Pointer enter event handler for the root element.