Content
Write pages, organize the sidebar, and add components and images.
Each MDX file in your content collection 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 Collections.
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.
press({
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({
integrations: [
press({ components: "./src/components/mdx.tsx" }),
],
});Use the Components
<Tabs items={["npm", "pnpm"]}>
<Tab value="npm">Install with npm.</Tab>
<Tab value="pnpm">Install with pnpm.</Tab>
</Tabs>Rules for MDX Components
The content of a page is a separate React island, so:
- Props must be serializable, since components hydrate by name.
<Chart data={[1, 2]} />runs in the browser, and<Chart onClick={() => {}} />renders on the server only. - Providers from your layout aren't available in the content. Add a
wrapperto the MDX components instead. - Imports are also loaded in the browser, so don't import server-only code.
No cycles
Don't import press.config.tsx or @fumapress/astro/runtime from the module. This creates an
import cycle with your content, which slows down the build.
MDX Components per Collection
press({
components: "./src/components/mdx.tsx",
collections: {
docs: { dir: "content/docs" },
blog: { dir: "content/blog", components: "./src/components/blog-mdx.tsx" },
},
});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} />;
}Astro renders your a component separately, like in Astro MDX, without hydration or React context
from the page. It can't use state, effects or hooks like usePathname. The same goes for an MDX
component inside a link.
Components per Page
List the content renderer yourself, with components as a function of the page. They go over the components of your module:
import { contentSourcePlugin } from "@fumapress/astro/plugins/content-source";
import { Mermaid } from "./src/components/mermaid";
createPress(content).plugins(
contentSourcePlugin({
components: (page) => (page.path.startsWith("guides/") ? { Mermaid } : {}),
}),
);page has the types of your content, and the rules for MDX components apply to these components too. 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:
On custom pages, use Astro Images.
---
import { Image } from "astro:assets";
import screenshot from "../assets/screenshot.png";
---
<Image src={screenshot} alt="A preview of the editor" />Last updated on