Skip to Content
Fumadocs

Markdown

How to write documents

Introduction

Fumadocs provides many useful extensions to MDX, a markup language. Here is a brief introduction to the default MDX syntax of Fumadocs.

MDX is not the only supported format of Fumadocs. In fact, you can use any renderer such as headless CMS.

See Custom Content Source for details.

MDX

We recommend MDX, a superset of Markdown with JSX syntax. It allows you to import components, and use them in the document, or even writing JavaScript.

See:

import { Component } from './component';

<Component name="Hello" />

## Heading

### Heading

#### Heading

Hello World, **Bold**, _Italic_, ~~Hidden~~

1. First
2. Second
3. Third

- Item 1
- Item 2

> Quote here

![alt](/image.png)

| Table | Description |
| ----- | ----------- |
| Hello | World       |

Frontmatter

Fumadocs support YAML-based frontmatter by default, title represents the page title (h1) in Fumadocs UI.

---
title: This is a document
---

...

For this reason, h1 title (# Heading) is usually unused when writing Markdown/MDX unless you have custom logic for page title rendering.

When your content source supports it, you can also export frontmatter in code. It is merged over the YAML frontmatter, and can read props:

---
title: Deploy
---

export const frontmatter = {
  description: `Deploy your ${props.framework} site.`,
};

In Fumadocs MDX

You can use the schema option to add frontmatter properties. See Customize Frontmatter for details.

Internal links use the <Link /> component of your React framework to allow prefetching and avoid hard-reload.

External links will get the default rel="noreferrer noopener" target="_blank" attributes for security.

[My Link](https://github.github.com/gfm)

This also works: https://github.github.com/gfm.

Cards

Useful for adding links.

import { HomeIcon } from 'lucide-react';

<Cards>
  <Card href="/docs" title="Documentation">
    Browse the full documentation.
  </Card>
  <Card title="href is optional">Cards can hold plain content too.</Card>
  <Card icon={<HomeIcon />} href="/" title="Home">
    You can include icons too.
  </Card>
</Cards>

Documentation

Browse the full documentation.

href is optional

Cards can hold plain content too.

Home

You can include icons too.

"Further Reading" Section

You can do something like:

page.tsx
import { getPageTreePeers } from 'fumadocs-core/page-tree';
import { source } from '@/lib/source';

<Cards>
  {getPageTreePeers(source.getPageTree(), '/docs/my-page').map((peer) => (
    <Card key={peer.url} title={peer.name} href={peer.url}>
      {peer.description}
    </Card>
  ))}
</Cards>;

This will show the other pages in the same folder as cards.

Callouts

Useful for adding tips/warnings, it is included by default. You can specify the type of callout:

  • info (default)
  • warn/warning
  • error
  • success
  • idea
<Callout>Hello World</Callout>

<Callout title="Title" type="warn">
  Hello World
</Callout>

<Callout title="Title" type="error">
  Hello World
</Callout>

<Callout title="Title" type="idea">
  Hello World
</Callout>
Hello World

Title

Hello World

Title

Hello World

Title

Hello World

Headings

An anchor is automatically applied to each heading, it sanitizes invalid characters like spaces. (e.g. Hello World to hello-world)

# Hello `World`

TOC Settings

The table of contents (TOC) will be generated based on headings, you can also customize the effects of headings:

# Heading [!toc]

This heading will be hidden from TOC.

# Another Heading [toc]

This heading will **only** be visible in TOC, you can use it to add additional TOC items.
Like headings rendered in a React component:

<MyComp />

Custom Anchor

You can add [#slug] to customize heading anchors.

# heading [#my-heading-id]

You can also chain it with TOC settings like:

# heading [toc] [#my-heading-id]

To link people to a specific heading, add the heading id to hash fragment: /page#my-heading-id.

Codeblock

Syntax Highlighting is supported by default using Rehype Code.

```js
console.log('Hello World');
```

```js title="My Title"
console.log('Hello World');
```

Line Numbers

Show line numbers, it also works with Twoslash and other transformers.

```ts twoslash lineNumbers
const a = 'Hello World';
//    ^?
console.log(a); 
```

You can set the initial value of line numbers.

```js lineNumbers=4
function main() {
  console.log('starts from 4');

  return 0;
}
```

Shiki Transformers

We support some of the Shiki Transformers, allowing you to highlight/style specific lines.

```tsx
// highlight a line
<div>Hello World</div> // [!code highlight]

// highlight a word
// [!code word:Fumadocs]
<div>Fumadocs</div>

// diff styles
console.log('hewwo'); // [!code --]
console.log('hello'); // [!code ++]

// focus
return new ResizeObserver(() => {}) // [!code focus]
```

Tab Groups

```ts tab="Tab 1"
console.log('A');
```

```ts tab="Tab 2"
console.log('B');
```
console.log('A');

To add a persist ID, define tab-group at the first codeblock:

```ts tab="Tab 1" tab-group="my-custom-group"
console.log('A');
```

```ts tab="Tab 2"
console.log('B');
```
console.log('A');

Another group:

console.log('A');

MDX in Tab Groups

Tab groups come from the remarkCodeTab remark plugin, which Fumadocs MDX enables by default. To use MDX in tab values, enable its parseMdx option:

source.config.ts
import { defineConfig } from 'fumadocs-mdx/config';

export default defineConfig({
  mdxOptions: {
    remarkCodeTabOptions: {
      parseMdx: true, 
    },
  },
});
```ts tab="<Building /> Tab 1"
console.log('A');
```

```ts tab="<Rocket /> Tab 2"
console.log('B');
```
console.log('A');

Include

Reference another file (can also be a Markdown/MDX document). Fumadocs MDX always enables it with Remark Include. Specify the target file path in <include> tag (relative to the MDX file itself).

page.mdx
<include>./another.mdx</include>

See other usages of include.

Props

The props of a page are available as props in MDX. For example, a page in a [framework] folder receives framework from its path params:

[framework]/deploy.mdx
## Deploy on {props.framework}

Deploy your {props.framework} site.

An expression is replaced by its value in the table of contents, the search index and the Markdown for LLMs as well. On the Astro page, the heading above gets the ID deploy-on-astro.

You can also pass custom props to a page.

Show

Render content on a condition. Fumadocs MDX enables it by default with Remark Show.

when is a JavaScript expression that can read props:

[framework]/deploy.mdx
<show when={props.framework === 'astro'}>

## Adapters

Add an adapter to your Astro config.

</show>

The section is only rendered on the page where framework is astro. On the other pages, it is also left out of the table of contents, the search index and the Markdown for LLMs.

You can use <show> around a step too:

[framework]/deploy.mdx
### Build [step]

<show when={props.framework === 'astro'}>

### Add an Adapter [step]

</show>

### Deploy [step]

Steps that aren't rendered are skipped in the numbering: Deploy is step 3 on the Astro page, and step 2 on the other pages.

It works the same way for a code block of a tab group. The tab only appears when its code block is rendered.

NPM Commands

Useful for generating commands for installing packages with different package managers.

```npm
npm i next -D
```

See remark-npm for details.

Steps

Useful for denoting steps for guides, see remark-steps for enable & configure.

### Installation [step]

### Write Code [step]

### Deploy [step]

Installation

Write Code

Deploy

Other Components

You can configure & use the built-in components in your MDX document, such as Tabs, Accordions and Zoomable Image.

Additional Features

You may be interested:

How is this guide?

Last updated on