---
title: Thread
description: Scrollable chat thread with stick-to-bottom behavior and an optional jump-to-bottom control
---
import ThreadDefault from "@/components/nexus-ui/examples/thread/default";
A viewport for stacked **[Message](/docs/components/message)** turns (or any content) that **sticks to the bottom** as content grows—built on [**use-stick-to-bottom**](https://github.com/stackblitz/use-stick-to-bottom). **`Thread`** wraps the scroll root, **`ThreadContent`** wraps the scrolling column, and **`ThreadScrollToBottom`** shows a control when the user has scrolled away from the bottom.
## Installation
```bash
npx shadcn@latest add @nexus-ui/thread
```
```bash
pnpm dlx shadcn@latest add @nexus-ui/thread
```
```bash
yarn dlx shadcn@latest add @nexus-ui/thread
```
```bash
bunx shadcn@latest add @nexus-ui/thread
```
Copy and paste the following code into your project.
Update the import paths to match your project setup.
## Usage
```tsx keepBackground
import {
Thread,
ThreadContent,
ThreadScrollToBottom,
} from "@/components/nexus-ui/thread";
```
```tsx keepBackground
{/* messages */}
```
**`ThreadScrollToBottom`** must be rendered **inside** **`Thread`** so it can read **`useStickToBottomContext`**.
## Vercel AI SDK Integration
Render [`useChat`](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) messages inside **Thread** by mapping the same **`messages`** array you would render with **[Message](/docs/components/message)** alone. Read each **[`UIMessage`](https://ai-sdk.dev/docs/reference/ai-sdk-core/ui-message)** **`parts`** array and join **`text`** parts for **MessageMarkdown** (streaming updates apply as the SDK appends or grows **`TextUIPart`** content).
See [Prompt Input](/docs/components/prompt-input#vercel-ai-sdk-integration) for a minimal **`POST /api/chat`** route with **`streamText`** and **`toUIMessageStreamResponse`**.
Install the AI SDK
```bash
npm install ai @ai-sdk/react @ai-sdk/openai
```
Create your chat API route
Use the same handler as in the Prompt Input docs: **`messages: await convertToModelMessages(messages)`** and **`return result.toUIMessageStreamResponse()`**.
Map `messages` to Message inside Thread
Use **`isTextUIPart`** from **`ai`** so you only aggregate **`type: "text"`** segments. Skip **`system`** turns unless you surface them deliberately. Assistant messages can also include **reasoning**, **tool**, **source**, and other part types—extend this loop when you need those in the UI.
```tsx
"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport, isTextUIPart, type UIMessage } from "ai";
import {
Message,
MessageStack,
MessageContent,
MessageMarkdown,
} from "@/components/nexus-ui/message";
import {
Thread,
ThreadContent,
ThreadScrollToBottom,
} from "@/components/nexus-ui/thread";
function textFromMessage(message: UIMessage) {
return message.parts.filter(isTextUIPart).map((p) => p.text).join("");
}
export default function ChatThread() {
const { messages } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
});
return (
{messages
.filter((m) => m.role !== "system")
.map((m) => (
{textFromMessage(m)}
))}
);
}
```
## API Reference
### Thread
Root scroll container wrapping [**`StickToBottom`**](https://github.com/stackblitz/use-stick-to-bottom). **`ThreadContent`** and **`ThreadScrollToBottom`** must live under **`Thread`** so the scrollable list and jump control share the same stick-to-bottom context.
number",
description: "Optional override to compute scroll top from layout.",
},
contextRef: {
type: "Ref",
description: "Optional ref to the library context object.",
},
instance: {
type: "StickToBottomInstance",
description: "Optional external instance from useStickToBottom.",
},
className: {
type: "string",
description: "Additional CSS classes to apply to the thread root.",
},
children: {
type: "ReactNode | ((context) => ReactNode)",
description:
"Typically ThreadContent plus ThreadScrollToBottom; render props receive the library context if needed.",
},
}}
/>
### ThreadContent
Wraps the transcript—usually **`Message`** rows—so **`Thread`** can keep the viewport following the bottom as new content arrives (**`StickToBottom.Content`**).
ReactNode)",
description: "Message list or other thread body.",
},
}}
/>
### ThreadScrollToBottom
Optional control that appears when the user has scrolled away from the bottom, so they can jump back to the latest messages. Supports polymorphism via **`asChild`**.