Without Config
Use the integration with your own routes and layouts.
Overview
Without src/fumadocs.config.ts, the integration only processes your MDX files and renders their content as a React island. You write the routes, layouts and providers.
Prefer the Fumadocs config, use this only when it doesn't cover your case yet, like routes rendered on demand, or integrations without a plugin like AsyncAPI. The layout, page and css options and plugins require the config file.
Setup
Follow Manual Installation until the source files, then register your MDX components with DocsBody as wrapper for content styles:
import defaultMdxComponents from 'fumadocs-ui/mdx';
import { DocsBody } from 'fumadocs-ui/layouts/docs/page';
import type { MDXComponents } from 'mdx/types';
export function getMDXComponents(components?: MDXComponents) {
return {
...defaultMdxComponents,
...components,
} satisfies MDXComponents;
}
export default getMDXComponents({ wrapper: DocsBody }); Provider
Fumadocs UI needs a provider in each React island:
import { navigate } from 'astro:transitions/client';
import type { ReactNode } from 'react';
import { RootProvider } from 'fumadocs-ui/provider/astro';
export interface ProviderProps {
/** `Astro.url.pathname` */
pathname: string;
/** `Astro.params` */
params: Record<string, string | undefined>;
children?: ReactNode;
}
export function Provider({ pathname, params, children }: ProviderProps) {
return (
<RootProvider pathname={pathname} params={params} navigate={navigate}>
{children}
</RootProvider>
);
}Docs Page
Render the docs layout as an island, with the content as children:
import { type SerializedPageTree, useFumadocsLoader } from 'fumadocs-core/source/client';
import type { TOCItemType } from 'fumadocs-core/toc';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
import { Provider, type ProviderProps } from '@/components/provider';
export interface DocsProps extends ProviderProps {
tree: SerializedPageTree;
title: string;
description?: string;
toc: TOCItemType[];
}
export function Docs({ tree, title, description, toc, children, ...props }: DocsProps) {
const data = useFumadocsLoader({ tree });
return (
<Provider {...props}>
<DocsLayout nav={{ title: 'My App' }} tree={data.tree}>
<DocsPage toc={toc}>
<DocsTitle>{title}</DocsTitle>
<DocsDescription>{description}</DocsDescription>
{children}
</DocsPage>
</DocsLayout>
</Provider>
);
}Search
Export the search index, the search dialog queries /api/search by default:
import type { APIRoute } from 'astro';
import { createFromSource } from 'fumadocs-core/search/server';
import { source } from '@/lib/source';
const server = createFromSource(source);
export const GET: APIRoute = () => server.staticGET();Pass a static search dialog to RootProvider, see Search UI.
Content Island
The content is its own React island, so your layout's providers don't reach it. wrapper receives <Content />'s props, add a provider there, without theme and search:
import { navigate } from 'astro:transitions/client';
import { RootProvider } from 'fumadocs-ui/provider/astro';
import type { ProviderProps } from '@/components/provider';
export default getMDXComponents({
wrapper: ({ pathname, params, children }: ProviderProps) => (
<RootProvider
pathname={pathname}
params={params}
navigate={navigate}
theme={{ enabled: false }}
search={{ enabled: false }}
>
<DocsBody>{children}</DocsBody>
</RootProvider>
),
});How is this guide?
Last updated on
