---
title: "AI chat"
description: "Let readers ask questions about your docs, answered from your pages."
url: https://docscn.dev/docs/components/ai-chat
lastModified: 2026-10-09T03:22:56.000Z
---

# AI chat (/docs/components/ai-chat)

> Let readers ask questions about your docs, answered from your pages.

<TryAIChat />

The demo above has no backend, so it plays a canned answer. Press <kbd>⌘</kbd> <kbd>/</kbd> to open the chat and <kbd>Esc</kbd> to close it.

## Installation [#installation]

The `ai-chat-openrouter` block adds the chat to your docs layout, with a chat route that searches your pages and answers through [OpenRouter](https://openrouter.ai):

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npx shadcn@latest add @docscn/ai-chat-openrouter
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm dlx shadcn@latest add @docscn/ai-chat-openrouter
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn dlx shadcn@latest add @docscn/ai-chat-openrouter
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun x shadcn@latest add @docscn/ai-chat-openrouter
    ```
  </CodeBlockTab>
</CodeBlockTabs>

It installs:

* `components/ai/chat/`: the chat UI (`@docscn/ai-chat`), where Fumadocs' CLI puts it
* `components/ai/search.tsx`: the chat state, from the AI SDK's `useChat`
* `components/ai/layout.tsx`: a client `DocsLayout` that passes the chat to `aiChat` and adds a floating **Ask AI** button
* `app/api/chat/route.ts`: the chat route

Then finish the setup:

1. Import `DocsLayout` from the client layout in `app/docs/layout.tsx`:

   ```tsx title="app/docs/layout.tsx"
   import { DocsLayout } from "@/components/docs/layouts/docs"; // [!code --]
   import { DocsLayout } from "@/components/ai/layout"; // [!code ++]
   ```

   For the [notebook layout](/docs/components/notebook-layout), change the import in `components/ai/layout.tsx` to `@/components/docs/layouts/notebook`.

2. Set your OpenRouter API key in `.env.local`. `OPENROUTER_MODEL` picks the model, `anthropic/claude-sonnet-5.5` by default:

   ```bash title=".env.local"
   OPENROUTER_API_KEY=...
   ```

The route searches each page's processed Markdown, so `lib/source.ts` needs `includeProcessedMarkdown`. The [`docs` block](/docs/getting-started) and `create-fumadocs-app` both turn it on:

```ts title="lib/source.ts"
const docs = defineDocs({
  dir: "content/docs",
  docs: {
    postprocess: {
      includeProcessedMarkdown: true,
    },
  },
});
```

To use another model provider, edit `app/api/chat/route.ts`. It's an [AI SDK](https://ai-sdk.dev) route, so any AI SDK provider works.

## Usage [#usage]

The chat UI is in `components/ai/chat`, and works with any AI SDK chat. `AIChatProvider` holds the open state and the chat, from `useChat`:

```tsx title="components/ai/search.tsx"
"use client";

import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import { AIChatProvider } from "./chat";

export function AIChat({ children }: { children: React.ReactNode }) {
  const chat = useChat({
    transport: new DefaultChatTransport({ api: "/api/chat" }),
  });

  return <AIChatProvider chat={chat}>{children}</AIChatProvider>;
}
```

Inside it, `useAIChat()` returns `{ open, setOpen }`. Pass `<AIChatPanel />` to the layout's [`aiChat`](/docs/components/docs-layout#ai-chat) option, as `components/ai/layout.tsx` does, and add `<AIChatTrigger />` for the floating button.

Each question is sent with the page it was asked from (`location` and `title`), as a `data-client` part. The chat route passes it to the model, so readers can ask about "this page".

### Parts [#parts]

The panel is built from parts you can arrange yourself:

* `AIChatHeader`: the chat's title, and buttons for a new chat and to close it
* `AIChatMessages`: the conversation. A new chat shows a description and suggested questions
* `AIChatInput`: the question form. Its draft is kept in `localStorage`
* `AIChatSearch`: a call of the route's `search` tool, which expands to the pages it found
* `AIChatSources`: a list of links to sources

## Props [#props]

### `AIChatProvider` [#aichatprovider]

<TypeTable
  type="{
  chat: {
    description: (
      <>
        The chat, from the AI SDK's <code>{&#x22;useChat()&#x22;}</code>.
      </>
    ),
    type: &#x22;UseChatHelpers<Message>&#x22;,
    required: true,
  },
  toMessage: {
    description: (
      <>
        The message to send for a question. By default, its text with the page
        it was asked from.
      </>
    ),
    type: '(text: string) => Parameters<UseChatHelpers<Message>[&#x22;sendMessage&#x22;]>[0]',
  },
  renderPart: {
    description: (
      <>
        Renders a message part other than text, such as a tool call. Keep it
        stable, so settled messages skip re-rendering.
      </>
    ),
    type: &#x22;(part, live: boolean) => ReactNode&#x22;,
  },
  description: {
    description: <>Shown under the title of a new chat.</>,
    type: &#x22;ReactNode&#x22;,
  },
  suggestions: {
    description: <>Questions suggested in a new chat.</>,
    type: &#x22;string[]&#x22;,
  },
}"
/>

## Translations [#translations]

The chat's strings use their own keys, as in Fumadocs' `@fumadocs/ai-chat`. Add them to your translations with `aiChatTranslations()`:

```ts title="lib/i18n.ts"
import { aiChatTranslations } from "@/components/ai/chat/i18n";
import { uiTranslations } from "@/components/docs/i18n";

export const translations = i18n
  .translations()
  .extend(uiTranslations())
  .extend(aiChatTranslations());
```

See [Internationalization](/docs/internationalization).

## Migrating from Fumadocs [#migrating-from-fumadocs]

A Fumadocs project that ran `fumadocs add ai` has the chat UI in `components/ai/chat/`, importing from `fumadocs-ui`. Install docscn's over it:

<CodeBlockTabs defaultValue="npm">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npx shadcn@latest add @docscn/ai-chat --overwrite
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm dlx shadcn@latest add @docscn/ai-chat --overwrite
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn dlx shadcn@latest add @docscn/ai-chat --overwrite
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun x shadcn@latest add @docscn/ai-chat --overwrite
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Your `components/ai/search.tsx`, `components/ai/layout.tsx` and chat route keep working: replacing `fumadocs-ui/` with `@/components/docs/` in your imports also updates the layout's.