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 renderers such as next-mdx-remote or CMS.

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:

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

import { Component } from './component';

<Component name="Hello" />

# Heading

## 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       |

Images are automatically optimized for next/image.

Internal links use the next/link component 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="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
    title="Fetching, Caching, and Revalidating"
  >
    Learn more about caching in Next.js
  </Card>
  <Card title="href is optional">Learn more about `fetch` in Next.js.</Card>
  <Card icon={<HomeIcon />} href="/" title="Home">
    You can include icons too.
  </Card>
</Cards>

"Further Reading" Section

You can do something like:

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

<Cards>
  {getPageTreePeers(source.pageTree, '/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
<Callout>Hello World</Callout>

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

<Callout title="Title" type="error">
  Hello World
</Callout>
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 customise 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 customise 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);
```
const a = 'Hello World';
const a: "Hello World"
.();

You can set the initial value of line numbers.

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

  return 0;
}
```
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]
```
// highlight a line
<div>Hello World</div>

// highlight a word
<div>Fumadocs</div>

// diff styles:
console.log('hewwo');
console.log('hello');

// focus
return new ResizeObserver(() => {}) 

Tab Groups

Make sure to add MDX components first:

mdx-components.tsx
import defaultMdxComponents from 'fumadocs-ui/mdx';
import * as TabsComponents from 'fumadocs-ui/components/tabs';
import type { MDXComponents } from 'mdx/types';

export function getMDXComponents(components?: MDXComponents): MDXComponents {
  return {
    ...defaultMdxComponents,
    ...TabsComponents,
    ...components,
  };
}
```ts tab="Tab 1"
console.log('A');
```

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

Include

This is only available on Fumadocs MDX.

Reference another file (can also be a Markdown/MDX document). Specify the target file path in <include> tag (relative to the MDX file itself).

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

See other usages.

Additional Features

You may be interested:

Package Install

Generate commands for installing packages via package managers.

```package-install
npm i next -D
```
npm i next -D
pnpm add next -D
yarn add next --dev
bun add next --dev

To enable, see Remark Install.

Tab Groups with MDX

You can use MDX inside tab values too, enable it the remark plugin:

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

export default defineConfig({
  mdxOptions: {
    remarkCodeTabOptions: {
      parseMdx: true,
    },
  },
});
import { compile } from '@mdx-js/mdx';
import { remarkCodeTab } from 'fumadocs-core/mdx-plugins';

await compile('...', {
  remarkPlugins: [
    [
      remarkCodeTab,
      {
        parseMdx: true,
      },
    ],
  ],
});
```ts tab="<Building /> Tab 1"
console.log('A');
```

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

How is this guide?