AI Composer
A chat surface for AI products: streaming replies, stop, retry, model picker, attachments and an auto-growing input.
Overview
Everything an AI chat needs, and nothing it doesn’t. Replies stream in token by token with a live cursor, and the send button becomes Stop while a response is generating. If a request fails, the error appears inline with a Retry that replays the last prompt with its history.
The composer grows with its content up to a comfortable limit. Enter sends, Shift + Enter adds a line, and IME composition is respected, so Japanese and Chinese input won’t send by accident. Attach up to five files as removable chips, switch models from the toolbar, and start from suggestions when the conversation is empty.
Bring any model. onSend gets the text, model, files and history, a token callback and an AbortSignal, so it works with fetch streams, the Vercel AI SDK, or your own server.
When to use
- A single interaction you want to feel finished, dropped into an existing screen.
When not to use
- A whole page layout: look at Sections or Templates.
Installation
pnpm dlx shadcn@latest add https://sundaeui.dev/r/ai-composer.jsonnpx shadcn@latest add https://sundaeui.dev/r/ai-composer.jsonyarn dlx shadcn@latest add https://sundaeui.dev/r/ai-composer.jsonbunx --bun shadcn@latest add https://sundaeui.dev/r/ai-composer.jsonWorks in any React project. Files are written to components/sundae/. Read the source in the stage’s Code view. Pro assets need a personal token. See authenticated installs.
- No dependencies beyond React 18 or later.
- Copy ai-composer.tsx into components/sundae/.
- Make sure Tailwind scans that folder (v4 detects it automatically; v3 needs it in `content`).
- Import the component and use it as shown below.
Usage
import { AiComposer } from '@/components/sundae/ai-composer'
<AiComposer
models={[{ id: 'balanced', name: 'Balanced' }]}
onSend={async ({ text, history }, onToken, signal) => {
const res = await fetch('/api/chat', { method: 'POST', body: JSON.stringify({ text, history }), signal })
const reader = res.body!.getReader()
const decoder = new TextDecoder()
for (;;) {
const { value, done } = await reader.read()
if (done) break
onToken(decoder.decode(value))
}
}}
/>Props
| Prop | Type | Default |
|---|---|---|
models*Options for the model picker. | { id, name, hint? }[] | — |
onSend*Stream a reply. Throw to show Retry, and stop when the signal aborts. | (input, onToken, signal) => Promise<void> | — |
suggestionsStarter prompts for the empty state. | string[] | — |
placeholderComposer placeholder. | string | — |
Accessibility
- The conversation is a polite role="log", so streamed text is announced as it settles.
- Send, Stop, Attach and Model all have labels. Errors use role="alert".
- Enter to send respects IME composition.
Customization
- Render Markdown in assistant messages by replacing the whitespace-pre-wrap block with your renderer.
- Raise the five-file attachment limit in onChange.
FAQ
- Is AI Composer free?
- AI Composer is part of Sundae Pro. The live preview is open to everyone; the source installs with a Pro account.
- How do I install AI Composer?
- Run npx shadcn@latest add https://sundaeui.dev/r/ai-composer.json. The files are written to components/sundae/. It has no dependencies beyond React 18 or later.
- Does AI Composer support keyboard and screen readers?
- The conversation is a polite role="log", so streamed text is announced as it settles. Send, Stop, Attach and Model all have labels. Errors use role="alert".
- Does AI Composer respect reduced motion?
- Yes. With prefers-reduced-motion set, decorative motion is removed and state changes are instant.
More like this
All components →- Pro
Team Members
Components · Understated Fold Accordion
Components · UnderstatedConfirm Dialog
Components · Understated- Pro
Notification Center
Components · Refined - Pro
Sheet Drawer
Components · Refined Avatar Stack
Components · Refined