Vite
React Router
Use Fumadocs MDX with React Router
Setup
npm i fumadocs-mdx fumadocs-core @types/mdx
Create the configuration file:
import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
dir: 'content/docs',
});
export default defineConfig();
Add the Vite plugin:
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()],
});
A source.generated.ts
file will be generated when you run development server or production build.
Accessing Content
You can import the source.generated.ts
file directly.
import { docs } from './source.generated';
console.log(docs);
To integrate with Fumadocs, create a docs collection and use:
import { loader } from 'fumadocs-core/source';
import { create, docs } from '../source.generated';
export const source = loader({
source: await create.sourceAsync(docs.doc, docs.meta),
baseUrl: '/docs',
});
Rendering Content
Rendering page content is different because React Router doesn't support RSC at the moment.
Instead, use toClientRenderer()
to lazy load MDX content as a component on browser.
For example:
import type { Route } from './+types/page';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import {
DocsBody,
DocsDescription,
DocsPage,
DocsTitle,
} from 'fumadocs-ui/page';
import { source } from '@/source';
import { type PageTree } from 'fumadocs-core/server';
import defaultMdxComponents from 'fumadocs-ui/mdx';
import { docs } from '../../source.generated';
import { toClientRenderer } from 'fumadocs-mdx/runtime/vite';
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,
tree: source.pageTree,
};
}
const renderer = toClientRenderer(
docs.doc,
({ toc, default: Mdx, frontmatter }) => {
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(props: Route.ComponentProps) {
const { tree, path } = props.loaderData;
const Content = renderer[path];
return (
<DocsLayout
nav={{
title: 'React Router',
}}
tree={tree as PageTree.Root}
>
<Content />
</DocsLayout>
);
}
How is this guide?
Last updated on