Sanity
Official integration for Sanity.
Overview
Fumadocs provides an official integration to simplify the setup of Sanity CMS.
You can see our Sanity Example on GitHub.
Setup
This guide assumes you already configured Sanity according to their docs.
Data Types
Run the following command to initialize content types.
npx @fumadocs/cli add sanity/baseOr you can run npx @fumadocs/cli add and browse additional Sanity presets to install.
Register the installed types:
import { docsType, blockContent, callout, card, cards } from '@/lib/sanity/base';
export const schemaTypes = [blockContent, callout, card, cards, docsType];Content Loader
Install the integration:
npm i @fumadocs/sanityCreate the source with the Sanity client:
import { dynamicLoader } from 'fumadocs-core/source';
import { createSanitySource } from '@fumadocs/sanity';
// the Sanity client
import { client } from '@/sanity/lib/client';
// the generated types
import type { Docs } from '@/sanity/types';
const source = dynamicLoader(
createSanitySource<Docs>({
client,
docType: 'docs',
}),
{
baseUrl: '/docs',
},
);
export async function getSource() {
return source.get();
}Now render pages with the getSource() function:
import { createFileRoute, notFound } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { useFumadocsLoader } from 'fumadocs-core/source/client';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
import { renderToc } from '@fumadocs/sanity/client';
import { getSource } from '@/lib/source';
import { CustomPortableText } from '@/components/sanity';
import type { PortableTextBlock } from '@portabletext/react';
// the type-level check of server function results can't verify Portable Text,
// register it as serializable (install `@tanstack/router-core` if it isn't resolvable)
declare module '@tanstack/router-core' {
interface SerializableExtensions {
portableTextBlock: PortableTextBlock;
}
}
export const Route = createFileRoute('/docs/$')({
component: Page,
loader: ({ params }) => serverLoader({ data: params._splat?.split('/') ?? [] }),
});
const serverLoader = createServerFn({
method: 'GET',
})
.validator((slugs: string[]) => slugs)
.handler(async ({ data: slugs }) => {
const source = await getSource();
const page = source.getPage(slugs);
if (!page) throw notFound();
const { title, description, _toc, body } = await page.data.load();
return {
title,
description,
toc: _toc,
body,
pageTree: await source.serializePageTree(source.getPageTree()),
};
});
function Page() {
const { title, description, toc, body, pageTree } = useFumadocsLoader(Route.useLoaderData());
return (
<DocsLayout tree={pageTree}>
<DocsPage toc={renderToc({ toc, render: (block) => <CustomPortableText value={block} /> })}>
<DocsTitle>{title}</DocsTitle>
<DocsDescription>{description}</DocsDescription>
<DocsBody>
<CustomPortableText value={body!} />
</DocsBody>
</DocsPage>
</DocsLayout>
);
}Done
Create documents under the docs type in your studio editor, and they appear in the docs route.
How is this guide?
Last updated on
