AI chat
Let readers ask questions about your docs, answered from your pages.
The demo above has no backend, so it plays a canned answer. Press ⌘ / to open the chat and Esc to close it.
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:
npx shadcn@latest add @docscn/ai-chat-openrouterIt installs:
components/ai/chat/: the chat UI (@docscn/ai-chat), where Fumadocs' CLI puts itcomponents/ai/search.tsx: the chat state, from the AI SDK'suseChatcomponents/ai/layout.tsx: a clientDocsLayoutthat passes the chat toaiChatand adds a floating Ask AI buttonapp/api/chat/route.ts: the chat route
Then finish the setup:
-
Import
DocsLayoutfrom the client layout inapp/docs/layout.tsx:app/docs/layout.tsx import { DocsLayout } from "@/components/docs/layouts/docs"; import { DocsLayout } from "@/components/ai/layout";For the notebook layout, change the import in
components/ai/layout.tsxto@/components/docs/layouts/notebook. -
Set your OpenRouter API key in
.env.local.OPENROUTER_MODELpicks the model,anthropic/claude-sonnet-5.5by default:.env.local OPENROUTER_API_KEY=...
The route searches each page's processed Markdown, so lib/source.ts needs includeProcessedMarkdown. The docs block and create-fumadocs-app both turn it on:
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 route, so any AI SDK provider works.
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:
"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 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
The panel is built from parts you can arrange yourself:
AIChatHeader: the chat's title, and buttons for a new chat and to close itAIChatMessages: the conversation. A new chat shows a description and suggested questionsAIChatInput: the question form. Its draft is kept inlocalStorageAIChatSearch: a call of the route'ssearchtool, which expands to the pages it foundAIChatSources: a list of links to sources
Props
AIChatProvider
Prop
Type
Translations
The chat's strings use their own keys, as in Fumadocs' @fumadocs/ai-chat. Add them to your translations with aiChatTranslations():
import { aiChatTranslations } from "@/components/ai/chat/i18n";
import { uiTranslations } from "@/components/docs/i18n";
export const translations = i18n
.translations()
.extend(uiTranslations())
.extend(aiChatTranslations());See Internationalization.
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:
npx shadcn@latest add @docscn/ai-chat --overwriteYour 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.