Vite
React Router
Use Fumadocs MDX with React Router
Setup
Installation
npm i fumadocs-mdx fumadocs-core @types/mdxCreate 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 { unstable_reactRouterRSC as reactRouterRSC } from '@react-router/dev/vite';
import rsc from '@vitejs/plugin-rsc';
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(),
    reactRouterRSC(),
    rsc(),
    tsconfigPaths(),
  ],
});Integrate with Fumadocs
To integrate with Fumadocs, make a lib/source.ts file:
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',
});The source.generated.ts file will be generated when you run development server or production build.
Done
You can now write content in content/docs folder.
Examples
Rendering Content
As React Router doesn't support RSC at the moment, use toClientRenderer() to lazy load MDX content as a component on browser.
For example:
import type { Route } from './+types/page';
import { source } from '@/lib/source';
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,
  };
}
const renderer = toClientRenderer(docs.doc, ({ default: Mdx, frontmatter }) => {
  return (
    <div className="prose">
      <h1>{frontmatter.title}</h1>
      <Mdx />
    </div>
  );
});
export default function Page(props: Route.ComponentProps) {
  const { path } = props.loaderData;
  const Content = renderer[path];
  return <Content />;
}Note that you can import the source.generated.ts file directly, it's useful to access compiled content without loader().
import { docs } from './source.generated';
console.log(docs);How is this guide?
Last updated on
