# Chat

A complete chat: messages, streaming replies, tool cards, suggestions, stop, retry and the composer. Connect it to your server or drive it with props.

- **Use it for**: A complete chat you can connect to your server, the AI SDK or your own state.
- **Not for**: Custom layouts that need the pieces arranged differently. Try [PromptInput](https://unseenui.com/components/prompt-input/), [Message](https://unseenui.com/components/message/), [StreamingResponse](https://unseenui.com/components/streaming-response/).

## Installation

```bash
npm install @stackunseen/ui
npx shadcn@latest add https://unseenui.com/r/chat.json
npx shadcn@latest add https://unseenui.com/r/chat-ai-sdk.json
```

## Parts

Chat puts four regions together. Each one is a library component you can also use on its own when you need a different layout.

1. **Header**: The title above the conversation, in the panel style only. The title also names the chat for screen readers. Props: `title`, `variant`.
2. **Transcript**: The messages: text, reasoning, files, sources and tool calls. Tools that need a person show an approval card underneath. It follows new messages and offers "Jump to latest" when you scroll up. With no messages it shows the empty state. Built from Message, StreamingResponse, ToolCall, ApprovalCard, MessageActions. Props: `messageVariant`, `responseVariant`, `renderTextPart`, `renderTool`, `renderMessageActions`, `feedback`, `onFeedback`, `onEdit`, `branches`, `onBranchChange`, `emptyTitle`, `emptyDescription`, `emptyContent`.
3. **Suggestions**: Prompts people can send with one click. Before the first message it shows your starters; after that, whatever the server offers. Hidden while a reply is running. Built from Suggestions. Props: `suggestions`, `starters`.
4. **Composer**: Where people type. It sends on Enter, turns into a stop button while a reply runs and can hold your own buttons, attachments, slash commands and mentions. Built from PromptInput. Props: `placeholder`, `composerHint`, `toolbar`, `attachments`, `commands`, `onCommand`, `mentions`, `onMention`, `maxPromptLength`.

- **Your server** (`host`): Pass a `host` and Chat follows it: messages, status, suggestions and approvals come from the host, and sends, stops and decisions go back to it. `useLocalHost` gives you a stand-in; `useAiSdkChat` adapts the AI SDK.
- **Your own state** (`messages`, `status`, `draft`, `onDraftChange`, `onSend`, `onCancel`, `onRetry`, `approvals`, `onDecision`): Or pass the conversation as props and handle each callback yourself. Use one way or the other, not both.

## Usage

```tsx
import { Chat } from '@stackunseen/ui/chat';
import '@stackunseen/ui/styles.css';
import '@stackunseen/ui/chat.css';

const host = useLocalHost();
return <Chat variant="panel" host={host} title="Assistant" />;
```

## All props

| Prop | Type | Description |
| --- | --- | --- |
| `approvals` | `readonly ChatApprovalRequest[]` |  |
| `attachments` | `ReactNode` |  |
| `branches` | `Readonly<Record<string, { index: number; total: number; }>>` | Other versions of a message (edits or regenerations), by message id. |
| `className` | `string` |  |
| `commands` | `readonly CommandOption[]` | "/" commands and "@" mentions in the composer; see PromptInput. |
| `composerHint` | `string` | A line shown under the composer, such as a notice; see PromptInput `hint`. |
| `draft` | `string` |  |
| `emptyContent` | `ReactNode` | Replaces the default empty state, for a start screen of your own. |
| `emptyDescription` | `string` |  |
| `emptyTitle` | `string` |  |
| `feedback` | `Readonly<Record<string, "helpful" \| "unhelpful">>` | Ratings already recorded, by message id. |
| `host` | `undefined \| ChatHost` |  |
| `maxPromptLength` | `number` |  |
| `mentions` | `readonly CommandOption[]` |  |
| `messages` | `readonly MessageData[]` |  |
| `messageVariant` | `"plain" \| "chat"` | How messages look: "plain" labels each speaker; "chat" puts your messages in right-aligned bubbles and replies in plain text, as ChatGPT does, with the speaker kept for screen readers. |
| `onBranchChange` | `((messageId: string, index: number) => void)` |  |
| `onCancel` | `(() => void)` |  |
| `onCommand` | `((command: CommandOption, value: string) => void)` |  |
| `onDecision` | `((decision: ChatApprovalDecision) => void)` |  |
| `onDraftChange` | `(draft: string) => void` |  |
| `onEdit` | `((messageId: string, text: string) => void)` | Lets people rewrite one of their messages; the host resends the conversation from there. |
| `onFeedback` | `((messageId: string, helpful: boolean) => void)` |  |
| `onMention` | `((item: CommandOption) => void)` |  |
| `onMentionQueryChange` | `((query: string \| null) => void)` |  |
| `onRetry` | `(() => void)` |  |
| `onSend` | `(text: string) => void` |  |
| `placeholder` | `string` |  |
| `renderMessageActions` | `((message: MessageData) => ReactNode)` | Extra actions under a finished reply, such as Read aloud or Share. |
| `renderTextPart` | `((part: TextMessagePart, variant: ComponentVariant<"StreamingResponse">) => ReactNode)` | Pass `renderMarkdownPart` from `@stackunseen/ui/markdown` to format replies. |
| `renderTool` | `((tool: ToolCallData) => ReactNode \| undefined)` | Your view for a tool call; return undefined to keep the default card. |
| `responseVariant` | `"cursor" \| "dots" \| "shimmer"` |  |
| `sources` | `readonly Source[]` |  |
| `starters` | `readonly string[]` | Prompts shown before the first message when the host offers none. |
| `status` | `ChatStatus` |  |
| `style` | `CSSProperties` |  |
| `suggestions` | `readonly string[]` |  |
| `title` | `string` | Shown above the transcript; also the accessible name. |
| `toolbar` | `ReactNode` | Composition slots for the composer. |
| `tools` | `readonly ToolCallData[]` |  |
| `variant` | `"panel" \| "plain"` |  |

## Keyboard

Enter sends and Shift+Enter adds a line; the transcript is a focusable log; suggestions and Retry are buttons.

## Works with

[PromptInput](https://unseenui.com/components/prompt-input/), [Message](https://unseenui.com/components/message/), [StreamingResponse](https://unseenui.com/components/streaming-response/), [MessageActions](https://unseenui.com/components/message-actions/), [Suggestions](https://unseenui.com/components/suggestions/), [Attachment](https://unseenui.com/components/attachment/), [FileDropzone](https://unseenui.com/components/file-dropzone/), [ModelSelector](https://unseenui.com/components/model-selector/), [FeedbackCapture](https://unseenui.com/components/feedback-capture/), [Reasoning](https://unseenui.com/components/reasoning/), [SuggestTextarea](https://unseenui.com/components/suggest-textarea/), [Checkpoint](https://unseenui.com/components/checkpoint/)

Page: https://unseenui.com/components/chat/
