A chat interface built on the editor: a centered thread, a rounded input with a bubble menu for formatting that cleans up pasted web content, copy, edit and regenerate actions on each message, streaming replies with a stop button, image attachments and an optional model picker.
Installation
$ pnpm dlx shadcn@latest add @editorcn-pro/chat-composer
Usage
onSend receives the user's message as Tiptap JSON. Return the reply as plain text, as Tiptap JSON, or as an async iterable of text chunks to stream it. The signal aborts when the user presses stop. Throw to mark the message as failed so it can be retried.
import { ChatComposer } from "@/components/templates/chat-composer";
export const Chat = () => (
<ChatComposer
onSend={async function* (content, { signal }) {
const res = await fetch("/api/chat", {
body: JSON.stringify(content),
method: "POST",
signal,
});
const reader = res.body!.pipeThrough(new TextDecoderStream()).getReader();
for (;;) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
}}
/>
);Attachments and models
Set attachments to let people add files with the + button, by pasting, or by dropping them on the input. Files arrive in onSend as files; uploading them is up to your backend. Pass models to show a model picker; the selected value arrives as model.
<ChatComposer
attachments
models={[
{ icon: <ClaudeIcon />, label: "Claude Opus", value: "claude-opus" },
{ icon: <ClaudeIcon />, label: "Claude Sonnet", value: "claude-sonnet" },
]}
onSend={(content, { files, model, signal }) =>
sendToYourApi({ content, files, model, signal })
}
/>Props
| Prop | Type | Description |
|---|---|---|
onSend | function | Gets the message, returns the reply |
initialMessages | ChatMessage[] | Messages shown on open |
attachments | boolean | Accept picked, pasted and dropped files |
accept | string | Allowed file types, default image/* |
maxFiles | number | Files per message, default 4 |
models | ChatModel[] | Items for the model picker |
defaultModel | string | Model value selected at first |
onModelChange | function | Gets the new model value |
suggestions | string[] | Prompts before the first message |
placeholder | string | Input placeholder |
disclaimer | string | Text under the input, "" hides it |
className | string | Outer container classes |