# Conversation

> An animated chat conversation for React and shadcn, following a streaming reply until you scroll up.

A chat thread that follows a streaming reply on one spring and lets go the moment you scroll up, raising a Jump to latest pill that turns into New reply when more arrives. Replies stream as markdown through Response (Streamdown), words sharpening from a soft blur.

- Tier: Eased Pro
- Interaction: Scroll
- Page: https://eased.dev/components/conversation
- Installs: motion, streamdown

## Install

Conversation ships with Eased Pro (https://eased.dev/#pricing). Members add the `@eased-pro` registry with their token (https://eased.dev/account), then run:

```bash
npx shadcn add @eased-pro/conversation
```

A chat thread: messages grouped by author, assistant replies streaming as markdown through Response, tool calls inline, and a viewport that follows the stream until you scroll away. `Response` (Streamdown with Eased styling) ships alongside it.

## When to use

- The message list of any AI chat fed by `useChat()`.
- `Response` on its own anywhere a model writes markdown.

## When not to use

- A static transcript with no streaming: render [Message](/components/message) in a plain list.

## Usage

```tsx example.tsx
import { useChat } from "@ai-sdk/react";
import { Conversation } from "@/components/eased/conversation/conversation";
import { Composer } from "@/components/eased/composer/composer";

const { messages, status, sendMessage, stop } = useChat();
<div className="flex h-full flex-col">
  <Conversation messages={messages} status={status} />
  <Composer status={status} onStop={stop} onSubmit={({ text }) => sendMessage({ text })} />
</div>
```

## API reference

### Conversation

| Prop | Type | Default | Description |
|---|---|---|---|
| `messages` | `ChatMessage[]` | | AI SDK `UIMessage`s. |
| `status` | `ChatStatus` | `"ready"` | `submitted` shows a thinking line; `streaming` animates the last reply. |
| `renderMessage` | `(m, { streaming, position }) => ReactNode` | | Replace the default rendering. |
| `empty` | `ReactNode` | | Shown with no messages. |
| `hasEarlier` / `onLoadEarlier` | | | "Load earlier" at the top; the view stays put as they prepend. |
| `thinkingLabel` | `string` | `"Thinking…"` | |
| `contentClassName` | `string` | `p-(--pad)` | Padding / max width of the column. |

### Response

`children` (markdown string), `isStreaming`, `components` (override any element), `className`. Code fences render as Eased Code Blocks.

## Keyboard

| Key | Action |
|---|---|
| `Tab` | Focuses the log (then arrows / Page keys scroll it), then the jump pill when shown. |

## Accessibility

- The list is `role="log"` with `aria-busy` while streaming, so screen readers announce a reply once it settles rather than word by word.

## Motion

Following rides one spring that is retargeted per chunk, so bursts glide; any scroll that isn't the spring's own lets go. The jump pill rises 8px from 0.97 on the snappy spring and leaves faster; its label text-swaps to "New reply" when content lands while you're away. New words in a reply fade in from a 4px blur over 150ms on the enter curve. Reduced motion: scrolling jumps, the pill fades, words appear without blur.

## Notes for AI

Pass `useChat()` straight in; tool parts render as Tool Call Rows automatically. Put the Composer below it in a flex column.

Do not add your own scroll-to-bottom effect or markdown renderer: both are built in.

## Related

- [Message](/components/message), [Composer](/components/composer), [Tool Call Row](/components/tool-call-row).
