Content
Write docs pages, and render them with MDX components.
Pages
Each MDX file in content/docs is a page, with the same page conventions and Markdown features as other Fumadocs apps.
URLs start with your source's baseUrl. With Astro's base, include it in baseUrl, like /my-base/docs.
Docs pages are generated at build time, or rendered on request with output: 'server' like other Astro pages.
Frontmatter
---
title: Setup
description: Install the app.
# use all available width
full: true
---To add custom fields, extend the collection schema:
import { defineCollection } from 'astro:content';
import { pageSchema } from 'fumadocs-core/source/schema';
import { metaLoader, pageLoader } from '@fumadocs/astro/loaders';
import { z } from 'astro/zod';
export const collections = {
docs: defineCollection({
loader: pageLoader(),
schema: pageSchema.extend({ draft: z.boolean().optional() }),
}),
meta: defineCollection({ loader: metaLoader() }),
};MDX Components
Pages render with Fumadocs UI components by default. To use your own, create a module whose default export is the MDX components:
import defaultMdxComponents from 'fumadocs-ui/mdx';
import type { MDXComponents } from 'mdx/types';
export function getMDXComponents(components?: MDXComponents) {
return {
...defaultMdxComponents,
...components,
} satisfies MDXComponents;
}
export default getMDXComponents();Rendering
The content of each page renders as one React island, so components share a React tree and hydrate like on other frameworks: code tabs, accordions, and JSX props like icon={<Icon />} work.
Parts that React can't render are rendered by Astro, inside the island:
- Highlighted code blocks.
- Images, processed by Astro's image pipeline.
- Components imported in the MDX file, Astro components included. Add
client:loadto hydrate framework components. {expressions}, they can't use your MDX components module.
MDX component props are serialized into the island and must be JSON-serializable. The island is its own React tree, so use wrapper to add providers.
Components outside the docs page island, like Graph View, need a framework provider of their own:
import { AstroProvider } from 'fumadocs-core/framework/astro';
import { navigate } from 'astro:transitions/client';
import { GraphView, type GraphViewProps } from './graph-view';
export function Graph({ pathname, ...props }: GraphViewProps & { pathname: string }) {
return (
<AstroProvider pathname={pathname} navigate={navigate}>
<GraphView {...props} />
</AstroProvider>
);
}Lazy Components
Every page loads your MDX components module. Wrap large components like <OpenAPIPage /> in lazy() so other pages skip them:
import { lazy } from 'react';
const OpenAPIPage = lazy(() => import('./api-page').then((mod) => ({ default: mod.OpenAPIPage })));
export function getMDXComponents(components?: MDXComponents) {
return {
...defaultMdxComponents,
OpenAPIPage,
...components,
} satisfies MDXComponents;
}Markdown
Configure Markdown on the integration. Astro's markdown config only applies to other Markdown files:
import { remarkMdxMermaid } from '@fumadocs/satteri/remark-mdx-mermaid';
fumadocs({
// syntax highlighting
rehypeCodeOptions: {
themes: { light: 'catppuccin-latte', dark: 'catppuccin-mocha' },
},
// Sätteri plugins, from `@fumadocs/satteri` or your own
mdastPlugins: [remarkMdxMermaid()],
});The built-in plugins accept the same options as Fumadocs MDX (see Built-in Plugins). See Configuration for all options. Include and heading IDs are enabled by default.
For Math, add @import 'katex/dist/katex.css'; to src/styles/global.css.
Collections
The integration processes content/docs by default. To add another directory like a blog, add it to collections:
fumadocs({
collections: {
docs: { dir: 'content/docs' },
blog: { dir: 'content/blog' },
},
});Each collection accepts integration options like its own components. For blog pages, see Blog.
Pages from other content sources join by passing a record of sources to loader(), like the pages generated by OpenAPI.
Other Content Sources
Other content sources work as your source. Pass their loader, for example with Local Markdown:
import { defineConfig } from '@fumadocs/astro/config';
import { loader } from 'fumadocs-core/source';
import { localMd } from '@fumadocs/local-md';
const docs = localMd({ dir: 'content/docs' });
export default defineConfig({
source: loader(await docs.staticSource(), { baseUrl: '/docs' }),
});Local Markdown, Local HTML, Obsidian and Python need no setup. Notion and Sanity render with a plugin:
import { notionPlugin } from '@fumadocs/astro/plugins/notion';
import { notion } from './lib/notion'; // your NotionIntegration
// `components` and `highlightCode` for rendering
notionPlugin(notion, { components, highlightCode });For a source with dynamicLoader(), pass await getSource().
Pages render with your MDX components, with relative links resolved. Add source-specific components like fumadocs-obsidian/ui so they render and hydrate.
How is this guide?
Last updated on
