Content
Write pages, organize the sidebar, and add components and images.
Each Markdown or MDX file under content/ is a page, and the sidebar lists them for you. Callouts, code block titles, tabs and other syntax work as in Fumadocs Markdown.
Pages
The URL of a page comes from its file path:
| File | URL |
|---|---|
content/index.mdx | / |
content/getting-started.mdx | /getting-started |
content/guide/install.mdx | /guide/install |
To put pages under a prefix like /docs, see Multiple Sources.
Frontmatter
---
title: Getting Started # required, the main heading of the page
description: Install and run the app. # below the title, and in the page metadata
icon: Rocket # a Lucide icon name for the sidebar
full: true # use the full width
---
## Install
Start the body at `##`, since `title` is the main heading.To resolve icon names, add the Lucide plugin of Fumadocs:
import { lucideIconsPlugin } from "fumadocs-core/source/plugins/lucide-icons";
export default createPress(content, {
loaderPlugins: [lucideIconsPlugin()],
});To add fields, extend the schema.
Links
Link to another page with its file path. Fumapress resolves it to the URL of that page:
Read the [install guide](./guide/install.mdx).Last Modified Date
Show the date of the last commit on each page. The sitemap and RSS feed also use this date.
const docs = defineDocs({
dir: "content",
docs: {
lastModified: true,
},
});The date comes from git history at build time, so uncommitted pages have no date. A shallow clone, common in CI, gives every page the date of the latest commit.
Sidebar
The sidebar lists your files by name. Add a meta.json next to them to set the order and labels:
{
"pages": ["index", "---Guides---", "getting-started", "guide"]
}See Page Slugs and Page Tree for separators, links, root folders and other syntax.
Components
Create the Module
Create a module that default-exports the components your pages can use:
import defaultMdxComponents from "fumadocs-ui/mdx";
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import type { MDXComponents } from "mdx/types";
export default {
...defaultMdxComponents,
Tab,
Tabs,
} satisfies MDXComponents;Register the Module
export default defineConfig({
plugins: [
press({ components: "./src/components/mdx.tsx" }),
fumadocsMdx(),
tailwindcss(),
],
});Use the Components
<Tabs items={["npm", "pnpm"]}>
<Tab value="npm">Install with npm.</Tab>
<Tab value="pnpm">Install with pnpm.</Tab>
</Tabs>You can also import a component directly in an MDX file.
Custom Links
Fumapress resolves relative links before your a component receives them, so your component only renders the link.
import type { ComponentProps } from "react";
export function DocsLink(props: ComponentProps<"a">) {
const external = props.href?.startsWith("http");
return <a {...props} target={external ? "_blank" : undefined} />;
}To use hooks like usePathname from fumadocs-core/framework, add "use client" to the component.
Components per Page
List the MDX renderer yourself, with components as a function of the page. It replaces the renderer that press() builds from your module:
import mdxPlugin from "fumadocs-mdx/press";
import components from "./src/components/mdx";
import { Mermaid } from "./src/components/mermaid";
createPress(content).plugins(
mdxPlugin({
components: (page) =>
page.path.startsWith("guides/") ? { ...components, Mermaid } : components,
}),
);page has the types of your content. The plugins of the Notion, Sanity and Obsidian sources take components as a function too.
Images and Files
Files in public/ are copied to the build as they are. public/screenshot.png is available at /screenshot.png. For a favicon, reference it from head.
Reference images from Markdown with an absolute path:
In components, import Image:
import { Image } from "fumapress/image";
<Image src="/screenshot.png" width={1200} height={630} alt="A preview of the editor" />;Besides the usual <img> props, Image takes:
Prop
Type
Image Optimization
Markdown images and Image are optimized when your platform supports image optimization. Without site.baseUrl, the self-hosted provider leaves images as they are.
| Platform | Provider | Needs |
|---|---|---|
| Vercel | Vercel Image Optimization | nothing |
| Cloudflare | Image Transformations | transformations enabled on your zone |
| Node.js | Self-hosted, with Sharp | sharp, a server and site.baseUrl |
Remote Images
Local paths are always allowed. For remote images, pass image: false to recommendedPreset() and add the provider with its options:
import { createPress, recommendedPreset } from "fumapress";
import { vercelImage } from "fumapress/plugins/image/vercel";
export const app = createPress(content).plugins(vercelImage({ domains: ["github.com"] }));
export default app.config({ preset: recommendedPreset({ image: false }) });Prop
Type
Disabling Optimization
On a static host with sharp installed, turn off image optimization, since the self-hosted provider needs a server:
import { createPress, recommendedPreset } from "fumapress";
export default createPress(content).config({
preset: recommendedPreset({ image: false }),
});For another optimizer, see Replacing a Default Plugin.
Last updated on