fumadocs-ui/provider/react-router package. It integrates with React Router’s navigation system and data loading patterns.
Installation
import { reactRouter } from '@react-router/dev/vite';
import tailwindcss from '@tailwindcss/vite';
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import mdx from 'fumadocs-mdx/vite';
import * as MdxConfig from './source.config';
export default defineConfig({
plugins: [
mdx(MdxConfig),
tailwindcss(),
reactRouter(),
tsconfigPaths({
projects: ['./tsconfig.json'],
}),
],
});
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router';
import { RootProvider } from 'fumadocs-ui/provider/react-router';
import './app.css';
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body className="flex flex-col min-h-screen">
<RootProvider>{children}</RootProvider>
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function App() {
return <Outlet />;
}
import type { Route } from './+types/docs';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
import { source } from '@/lib/source';
import defaultMdxComponents from 'fumadocs-ui/mdx';
import browserCollections from 'fumadocs-mdx:collections/browser';
import { baseOptions } from '@/lib/layout.shared';
import { useFumadocsLoader } from 'fumadocs-core/source/client';
export async function loader({ params }: Route.LoaderArgs) {
const slugs = params['*'].split('/').filter((v) => v.length > 0);
const page = source.getPage(slugs);
if (!page) throw new Response('Not found', { status: 404 });
return {
path: page.path,
url: page.url,
pageTree: await source.serializePageTree(source.getPageTree()),
};
}
const clientLoader = browserCollections.docs.createClientLoader({
component({ toc, frontmatter, default: Mdx }, { path, url }: { path: string; url: string }) {
return (
<DocsPage toc={toc}>
<title>{frontmatter.title}</title>
<meta name="description" content={frontmatter.description} />
<DocsTitle>{frontmatter.title}</DocsTitle>
<DocsDescription>{frontmatter.description}</DocsDescription>
<DocsBody>
<Mdx components={{ ...defaultMdxComponents }} />
</DocsBody>
</DocsPage>
);
},
});
export default function Page({ loaderData }: Route.ComponentProps) {
const { path, url, pageTree } = useFumadocsLoader(loaderData);
return (
<DocsLayout {...baseOptions()} tree={pageTree}>
{clientLoader.useContent(path, { path, url })}
</DocsLayout>
);
}
import type { Config } from '@react-router/dev/config';
import { glob } from 'node:fs/promises';
import { createGetUrl, getSlugs } from 'fumadocs-core/source';
const getUrl = createGetUrl('/docs');
export default {
ssr: true,
async prerender({ getStaticPaths }) {
const paths: string[] = [];
for await (const entry of glob('**/*.mdx', { cwd: 'content/docs' })) {
const slugs = getSlugs(entry);
paths.push(getUrl(slugs));
}
return paths;
},
} satisfies Config;
Framework Provider
TheReactRouterProvider integrates Fumadocs with React Router’s navigation:
useLocation()for pathname trackinguseNavigate()for programmatic navigationuseRevalidator()for data revalidationuseParams()for route parametersLinkcomponent with prefetch support