# Chat Layout
Build AI chat interfaces with message streams, reasoning, tool calling, and Vercel AI SDK integration.
## When to use
- AI chatbot interfaces
- Customer support chat
- Any conversational UI with streaming responses
## Setup
### Install dependencies
**Nuxt:**
```bash
pnpm add ai @ai-sdk/gateway @ai-sdk/vue @comark/nuxt
```
**Vue (Vite):**
```bash
pnpm add ai @ai-sdk/gateway @ai-sdk/vue @comark/vue
```
### Register Comark module
**Nuxt:**
```ts [nuxt.config.ts]
export default defineNuxtConfig({
modules: [
'@nuxt/ui',
'@comark/nuxt'
]
})
```
**Vue (Vite):** No module registration needed, import directly from `@comark/vue`.
> `@comark/nuxt` (or `@comark/vue` for Vue projects) provides the `Comark` component used to render AI responses as streaming Markdown, it incrementally renders tokens as they arrive and automatically enables Nuxt UI's prose components.
### Dark mode for syntax highlighting
When using the `highlight` plugin, add the following CSS to your stylesheet:
```css [main.css]
html.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
```
### Server endpoint
Using [Vercel AI Gateway](https://vercel.com/ai-gateway) (recommended):
```ts [server/api/chat.post.ts]
import { streamText, convertToModelMessages, toUIMessageStream, createUIMessageStreamResponse } from 'ai'
import { gateway } from '@ai-sdk/gateway'
export default defineEventHandler(async (event) => {
const { messages } = await readBody(event)
const result = streamText({
model: gateway('anthropic/claude-sonnet-5'),
instructions: 'You are a helpful assistant.',
messages: await convertToModelMessages(messages)
})
const stream = toUIMessageStream({ stream: result.stream })
return createUIMessageStreamResponse({ stream })
})
```
Or with a direct provider (e.g., `pnpm add @ai-sdk/openai`):
```ts [server/api/chat.post.ts]
import { streamText, convertToModelMessages, toUIMessageStream, createUIMessageStreamResponse } from 'ai'
import { openai } from '@ai-sdk/openai'
export default defineEventHandler(async (event) => {
const { messages } = await readBody(event)
const result = streamText({
model: openai('gpt-5-nano'),
instructions: 'You are a helpful assistant.',
messages: await convertToModelMessages(messages)
})
const stream = toUIMessageStream({ stream: result.stream })
return createUIMessageStreamResponse({ stream })
})
```
## Component tree
```
UDashboardPanel
├── #header → UDashboardNavbar
├── #body → UContainer → UChatMessages
│ ├── #content → UChatReasoning, UChatTool, Comark
│ └── #indicator (loading)
└── #footer → UContainer → UChatPrompt
└── UChatPromptSubmit
```
## Full page chat
```vue [pages/chat/[id].vue]
{{ part.text }}
```
## Key components
- `UChatMessages` — scrollable message list with auto-scroll. Props: `messages`, `status`. Slots: `#content` (per message), `#actions`, `#indicator`.
- `UChatMessage` — individual bubble. Props: `message`, `side` (`'left'`/`'right'`).
- `UChatReasoning` — collapsible reasoning block. Auto-opens during streaming, auto-closes when done. Use `isPartStreaming(part)` from `@nuxt/ui/utils/ai`.
- `UChatTool` — tool invocation status. Use `isToolStreaming(part)`. Variants: `'inline'` (default), `'card'`.
- `UChatPrompt` — enhanced textarea for chat. Its typed API exposes a selected subset of `UTextarea` props, forwards additional attributes to the underlying textarea, and adds chat-specific props such as `error` and `submitOnEnter`.
- `UChatPromptSubmit` — submit button with automatic status handling (send/stop/reload).
- `UChatPalette` — layout wrapper for chat inside overlays.
## Chat in a modal
```vue
```
## With model selector
```vue
```
## Conversation sidebar
Combine with dashboard layout for a ChatGPT-like interface:
```vue [layouts/dashboard.vue]
```