GitHubnpm

Accent theme

Base radius

GitHubnpm

Accent theme

Base radius

Colour scheme
Docs menu

Guides


Primitives
Forms
Layout
Feedback
Overlays
Navigation
Data Display
AI

Composer

A chat message input: a real <textarea> that grows with field-sizing: content (no form — a composer submits on a keystroke or a button, never page navigation), with leading/trailing action slots and a thinking state for when a response is in flight.

Examples

Basic

Just a placeholder — Cmd/Ctrl+Enter submits by default.

Usage
<Composer placeholder="Ask anything…" />

With actions

Leading/trailing slots for attachments, a send button, anything else.

Usage
<Composer
  placeholder="Ask anything…"
  actionsLeading={
    <Button variant="ghost" size="sm" aria-label="Attach" iconStart={<PaperclipIcon />} />
  }
  actionsTrailing={({ submit }) => (
    <Button variant="primary" size="sm" onClick={submit}>
      Send
    </Button>
  )}
/>

Thinking state

An animated border sweep signals an in-flight response and blocks submission. The submitted query stays visible.

Usage
<Composer
  placeholder="Ask anything…"
  defaultValue="How do I theme Kernel with a custom accent colour?"
  thinking
/>

Playground

Toggle every adjustable prop and watch the component — and the code — update live.

submitOn
thinking
disabled
Usage
<Composer placeholder="Ask anything…" />

Props

Props for Composer.
PropTypeDefault
value / defaultValuestring
onValueChange(value: string) => void
onSubmit(value: string) => void
submitOn"mod+enter" | "enter""mod+enter"
placeholderstring
disabledbooleanfalse
thinkingbooleanfalse
actionsLeading / actionsTrailingReactNode | (ctx: { submit: () => void }) => ReactNode

Accessibility

  • The textarea gets an aria-label from placeholder when no visible label is present.
  • Growth is pure CSS (field-sizing: content), so there's no layout thrash or focus loss as content grows.
  • The thinking-state border sweep is decorative (aria-hidden via pointer-events: none and no text content) and freezes under prefers-reduced-motion, replaced by a static tinted border — the state is still visible, just not animated.