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.
Examples
Section titled “Examples”<div className={containerStyle}> <ChatComposer {...args} /></div>With Slots
Section titled “With Slots”<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>Stop Mode
Section titled “Stop Mode”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 />Error Status
Section titled “Error Status”<div className={containerStyle}> <ChatComposer {...args} status={{message: 'Message failed to send. Retry?', type: 'error'}} /></div>Warning Status Top
Section titled “Warning Status Top”<div className={containerStyle}> <ChatComposer {...args} status={{ message: 'The context window is almost full.', type: 'warning', }} statusPosition="top" /></div>Controlled
Section titled “Controlled”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 />Disabled
Section titled “Disabled”<div className={containerStyle}> <ChatComposer {...args} /></div>ChatComposer
Section titled “ChatComposer”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.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | 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. |
footerActions | ReactNode | — | Actions rendered at the start of the footer row. |
headerActions | ReactNode | — | Actions rendered at the start of the header row (e.g. attach buttons). |
headerContext | ReactNode | — | Contextual info rendered at the end of the header row. |
input | ReactNode | — | Custom input element that replaces the default ChatComposerInput. |
isDisabled | boolean | false | Whether the composer is disabled. |
isStopShown | boolean | false | Whether 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. |
placeholder | string | 'Type a message…' | Placeholder text for the input. |
ref | Ref<HTMLDivElement> | — | Ref forwarded to the root element. |
sendActions | ReactNode | — | Actions rendered directly before the send button. |
sendButton | ReactNode | — | Custom send button that replaces the default ChatSendButton. |
status | ChatComposerStatus | — | Status message rendered attached to the composer body. |
statusPosition | 'bottom' | 'top' | 'bottom' | Which edge of the composer the status attaches to. |
style | CSSProperties | — | Inline styles applied to the root element. |
value | string | — | Controlled input value. When set, the parent owns the value and should clear it in onSubmit. |
aria-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |
ChatComposerInput
Section titled “ChatComposerInput”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.
| Prop | Type | Default | Description |
|---|---|---|---|
autoComplete | string | — | HTML autocomplete attribute for the textarea. |
className | string | — | Additional CSS class names applied to the textarea. |
data-testid | string | — | Test ID applied to the textarea. |
enterKeyHint | TextareaHTMLAttributes<HTMLTextAreaElement>['enterKeyHint'] | — | Action label shown on the virtual keyboard's enter key. |
isDisabled | boolean | false | Whether the input is disabled. Defaults to the surrounding ChatComposer state. |
maxLength | number | — | Maximum number of characters the user can type. |
maxRows | number | 8 | Maximum number of lines the input grows to before scrolling. |
minRows | number | 1 | Minimum number of lines the input occupies. |
name | string | — | HTML name attribute for form submission. |
onBlur | FocusEventHandler<HTMLTextAreaElement> | — | Blur event handler for the textarea. |
onChange | (value: string) => void | — | Called when the value changes. Defaults to the surrounding ChatComposer state. |
onFocus | FocusEventHandler<HTMLTextAreaElement> | — | Focus event handler for the textarea. |
onKeyDown | KeyboardEventHandler<HTMLTextAreaElement> | — | Keyboard event handler for the textarea, called before the built-in Enter-to-submit handling. Call preventDefault() to suppress it. |
onPaste | ClipboardEventHandler<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. |
placeholder | string | 'Type a message…' | Placeholder text. Defaults to the surrounding ChatComposer placeholder. |
ref | Ref<HTMLTextAreaElement> | — | Ref forwarded to the textarea element. |
style | CSSProperties | — | Inline styles applied to the textarea. |
value | string | — | Controlled value. Defaults to the surrounding ChatComposer value. |
aria-describedby | AriaAttributes['aria-describedby'] | — | Identifies the element(s) that describe the region. |
aria-label | AriaAttributes['aria-label'] | — | Accessible label for the region. |
aria-labelledby | AriaAttributes['aria-labelledby'] | — | Identifies the element(s) that label the region. |
id | string | — | HTML id attribute applied to the root element. |
ChatSendButton
Section titled “ChatSendButton”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.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS class names applied to the button. |
data-testid | string | — | Test ID applied to the button. |
isDisabled | boolean | — | Whether the send button is disabled. Defaults to !canSend from the surrounding ChatComposer. |
isStopShown | boolean | false | Whether 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. |
ref | Ref<HTMLElement> | — | Ref forwarded to the button element. |
sendIcon | IconComponent | ArrowUp | Icon for the send state. |
size | 'md' | 'sm' | 'md' | Button size. |
stopIcon | IconComponent | Square | Icon for the stop state. |
style | CSSProperties | — | Inline styles applied to the button. |
form | string | — | HTML form attribute associating the button with a <form> by ID. |
id | string | — | HTML id attribute applied to the root element. |
aria-controls | string | — | Identifies the element(s) whose contents are controlled by the button. |
aria-describedby | string | — | Identifies the element(s) that describe the button. |
aria-details | string | — | Identifies the element that provides a detailed description. |
aria-expanded | boolean | — | Indicates whether a controlled element is expanded or collapsed. |
aria-haspopup | boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | — | Indicates the button opens an interactive popup element. |
aria-keyshortcuts | string | — | Keyboard shortcuts that activate or focus the button. |
aria-labelledby | string | — | Identifies the element(s) that label the button. |
onFocus | FocusEventHandler<HTMLElement> | — | Focus event handler for the root element. |
onKeyDown | (event: KeyboardEvent<HTMLElement>) => void | — | Keyboard event handler for the root element. |