Fumadocs

Layouts

Customize the navbar, the docs page and custom pages.

Overview

The integration renders pages with Fumadocs UI layouts. You customize them with React modules that run in the browser as islands:

ModuleExports
layoutbaseOptions(), layout options, and Provider.
pageThe docs page component, as default export.

Layout Options

Create a module exporting baseOptions(), which returns the layout options, JSX included:

import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
import { appName, gitConfig } from './shared';

export function baseOptions(): BaseLayoutProps {
  return {
    nav: {
      // JSX supported
      title: appName,
    },
    githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`,
  };
}

The options apply to every layout: docs pages, custom pages and the 404 page.

Without it, the navbar shows your Fumadocs config's title.

Provider

The integration renders the root provider for you. To render components inside it like WebMCP, export Provider from the layout module:

src/lib/layout.shared.tsx
import type { ReactNode } from 'react';
import { WebMCP } from '@/components/webmcp';

export function Provider({ children }: { children: ReactNode }) {
  return (
    <>
      <WebMCP />
      {children}
    </>
  );
}

It wraps every layout, but not the content components -- those render in their own islands.

Docs Page

The docs page is a React component, like page.tsx on other frameworks. Create a module whose default export renders it:

import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import {
  DocsDescription,
  DocsPage,
  DocsTitle,
  MarkdownCopyButton,
  PageLastUpdate,
  ViewOptionsPopover,
} from 'fumadocs-ui/layouts/docs/page';
import type { DocsPageProps } from '@fumadocs/astro/config';

/**
 * The docs page, the content is passed as children.
 */
export default function Docs({ tree, page, layout, children }: DocsPageProps) {
  return (
    <DocsLayout {...layout} tree={tree}>
      <DocsPage toc={page.toc} full={page.full}>
        <DocsTitle>{page.title}</DocsTitle>
        <DocsDescription>{page.description}</DocsDescription>
        {page.markdownUrl && (
          <div className="flex flex-row gap-2 items-center border-b -mt-4 pb-6">
            <MarkdownCopyButton markdownUrl={page.markdownUrl} />
            <ViewOptionsPopover markdownUrl={page.markdownUrl} githubUrl={page.githubUrl} />
          </div>
        )}
        {children}
        {page.lastModified && <PageLastUpdate date={page.lastModified} />}
      </DocsPage>
    </DocsLayout>
  );
}

It receives:

  • tree: the page tree.
  • layout: the baseOptions() result.
  • page: page data.
  • children: the content.

Prop

Type

Use any Fumadocs UI layout or component here, such as the Notebook layout for some pages:

src/components/docs.tsx
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsLayout as NotebookLayout } from 'fumadocs-ui/layouts/notebook'; 
import type { DocsPageProps } from '@fumadocs/astro/config';

export default function Docs({ tree, page, layout, children }: DocsPageProps) {
  // `type` is the key of its source in `loader()`
  const Layout = page.type === 'api' ? NotebookLayout : DocsLayout;
  // ...
}

Custom Pages

Use HomeLayout.astro for custom pages, with the navbar from your layout options:

src/pages/index.astro
---
import HomeLayout from '@fumadocs/astro/components/HomeLayout.astro';
---

<HomeLayout>
  <main class="flex flex-col flex-1 items-center justify-center gap-4 text-center">
    <h1 class="text-xl font-bold">Fumadocs on Astro.</h1>
    <a class="underline" href="/docs">Open Docs</a>
  </main>
</HomeLayout>

Anything in its head slot goes into <head>. Props: title, description, lang (for internationalization) and notFound.

Your pages can read your docs from the source:

src/pages/all.astro
---
import HomeLayout from '@fumadocs/astro/components/HomeLayout.astro';
import { source } from '@/lib/source';
---

<HomeLayout title="All Pages">
  <ul>
    {source.getPages().map((page) => <li><a href={page.url}>{page.data.title}</a></li>)}
  </ul>
</HomeLayout>

A custom page takes priority over a docs page at the same URL. Remove the MDX file to avoid a warning from Astro. To replace the 404 page, create src/pages/404.astro.

React Content

Render React content with ReactContent.astro to hydrate it like docs content: it renders on the server and your MDX components hydrate, like code block copy buttons.

src/pages/changelog.astro
---
import { createElement } from 'react';
import HomeLayout from '@fumadocs/astro/components/HomeLayout.astro';
import ReactContent from '@fumadocs/astro/components/ReactContent.astro';
import { Timeline } from '@/components/timeline';
---

<HomeLayout title="Changelog">
  <ReactContent node={createElement(Timeline)} />
</HomeLayout>

Add tags to the <head> of every page with an Astro component:

<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

On docs pages, it receives page data as page.

Styles

The pages load src/styles/global.css, see Themes for its colors and presets. Set css for another file:

astro.config.mjs
fumadocs({
  css: './src/styles/docs.css', 
});

How is this guide?

Last updated on