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
classNamestringAdditional CSS class names applied to the root element.
data-testidstringTest ID applied to the root element.
density"compact" | "balanced" | "spacious"'balanced'Density preset controlling body padding and gaps. Defaults to the surrounding ChatLayout density.
footerActionsReactNodeActions rendered at the start of the footer row.
headerActionsReactNodeActions rendered at the start of the header row (e.g. attach buttons).
headerContextReactNodeContextual info rendered at the end of the header row.
inputReactNodeCustom 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) => voidCalled when the input value changes.
onStop() => voidCalled when the user clicks the stop button.
onSubmit*(value: string) => voidCalled 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.
sendActionsReactNodeActions rendered directly before the send button.
sendButtonReactNodeCustom send button that replaces the default ChatSendButton.
statusChatComposerStatusStatus message rendered attached to the composer body.
statusPosition'bottom' | 'top''bottom'Which edge of the composer the status attaches to.
styleCSSPropertiesInline styles applied to the root element.
valuestringControlled 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.
idstringHTML 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
autoCompletestringHTML autocomplete attribute for the textarea.
classNamestringAdditional CSS class names applied to the textarea.
data-testidstringTest 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.
maxLengthnumberMaximum number of characters the user can type.
maxRowsnumber8Maximum number of lines the input grows to before scrolling.
minRowsnumber1Minimum number of lines the input occupies.
namestringHTML name attribute for form submission.
onBlurFocusEventHandler<HTMLTextAreaElement>Blur event handler for the textarea.
onChange(value: string) => voidCalled 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() => voidCalled 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.
styleCSSPropertiesInline styles applied to the textarea.
valuestringControlled 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.
idstringHTML 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
classNamestringAdditional CSS class names applied to the button.
data-testidstringTest ID applied to the button.
isDisabledbooleanWhether 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() => voidCalled when the user clicks the send button. Defaults to submitting the surrounding ChatComposer.
onStop() => voidCalled 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.
styleCSSPropertiesInline styles applied to the button.
formstringHTML form attribute associating the button with a <form> by ID.
idstringHTML id attribute applied to the root element.
aria-controlsstringIdentifies the element(s) whose contents are controlled by the button.
aria-describedbystringIdentifies the element(s) that describe the button.
aria-detailsstringIdentifies the element that provides a detailed description.
aria-expandedbooleanIndicates whether a controlled element is expanded or collapsed.
aria-haspopupboolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'Indicates the button opens an interactive popup element.
aria-keyshortcutsstringKeyboard shortcuts that activate or focus the button.
aria-labelledbystringIdentifies the element(s) that label the button.
onFocusFocusEventHandler<HTMLElement>Focus event handler for the root element.
onKeyDown(event: KeyboardEvent<HTMLElement>) => voidKeyboard event handler for the root element.