ChatComposer
ChatComposer
const [pending, setPending] = useState(false);<ChatComposer isSending={pending} beforeInput={<IconButton aria-label="Attach"><PaperclipIcon /></IconButton>} attachments={files.map((f) => <AttachmentTile key={f.id} name={f.name} size={f.size} onRemove={() => remove(f.id)} />)} onSend={async (text) => { setPending(true); await send(text); setPending(false); }}/>Install: @helixui/core
import { ChatComposer } from '@helixui/core'status: stable · since: 0.3.0
Tags: input, message, send, ai, multiline
Anatomy
┌────────────────────────────────────────┐│ [📎] | Type a message... [↑] ││ (auto-resize, Enter sends) │└────────────────────────────────────────┘Layout
- display —
block - width —
fill - height —
content - intrinsicSize —
min ~48px, grows up to maxHeight on multi-line - stackable —
false - fullBleed —
false
Visual
A rounded surface (radius.lg) holding a multi-line textarea, optional attachment button on the left, and a brand-colored send button on the right. Auto-grows up to a max height, then scrolls inside. Enter sends; Shift+Enter inserts a newline.
Props
| Name | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled message text. |
defaultValue | string | — | Uncontrolled initial text. |
onChange | (v: string) => void | — | Called on every keystroke. |
onSend | (v: string) => void | — | Called when the user presses Enter or clicks send. Receives the trimmed message. |
placeholder | string | Send a message… | Placeholder. |
isDisabled | boolean | false | Disable the entire composer. |
isSending | boolean | false | While true, the send button is disabled (use during request). |
attachments | ReactNode | — | Slot above the input — attachment chips, mentions. |
beforeInput | ReactNode | — | Slot to the left of the input (formatting toolbar, attach button). |
afterInput | ReactNode | — | Slot to the right of the input, before the send button. |
sendIcon | ReactNode | — | Override the default paper-plane icon. |
sendLabel | string | Send | aria-label on the send button. |
minRows | number | 1 | Auto-resize floor. |
maxRows | number | 8 | Auto-resize ceiling; scrolls beyond. |
Tokens used
color.bg.surface.default, color.bg.surface.muted, color.bg.action.brand.default, color.bg.action.brand.hover, color.bg.action.neutral.default, color.text.primary, color.text.on.brand, color.text.muted, color.border.default, color.border.focus, radius.lg, radius.full, space.1, space.2, space.3, font.family.sans, font.size.md
Accessibility
Keyboard
| Key | Action |
|---|---|
Enter | Send the message. |
Shift+Enter | Insert newline. |
Notes
- The send button is disabled when the message is empty or whitespace.
- IME composition is respected —
Enterdoes not send while composing (Korean/Japanese/Chinese input).
Composes with
| Component | Relation | Note |
|---|---|---|
AttachmentTile | child | Renders attached files inside the composer. |
PromptSuggestions | sibling | Suggestions appear above the composer. |
ChatList | sibling | Sits below the chat list scroll area. |
ChatMessage | sibling | |
IconButton | sibling |
Prompt examples
These are the AI prompt → JSX mappings used by the helixui prompt DSL and integrations like Cursor / Claude Code.
AI chat input
“composer that sends on Enter”
<ChatComposer onSend={handleSend} placeholder="Ask anything…" />with attachments
“composer with paperclip”
<ChatComposer onSend={handleSend} onAttach={handleAttach} />