Fumadocs

Highlighter

Highlight code with Shiki, or a highlighter of your choice.

Fumadocs highlights code with Shiki by default. You can create a highlighter and pass it to the places that highlight code instead, Shiki isn't loaded then.

lib/highlighter.ts
// npm i @pierre/highlights
import { createHighlights } from 'fumadocs-core/highlight/highlights';
import githubLight from '@pierre/highlights/themes/github-light';
import githubDark from '@pierre/highlights/themes/github-dark';

export const highlighter = createHighlights({
  themes: { light: githubLight, dark: githubDark },
});

Highlights is written in WebAssembly and many times faster than Shiki. It has 80 languages built in (others are highlighted as plain text), uses its own themes from @pierre/highlights/themes, and runs Shiki transformers through shikiTransformers, a compatibility layer.

highlighter.override() creates a highlighter with other options, like other transformers.

Usage

source.config.ts
import { defineConfig } from 'fumadocs-mdx/config';
import { rehypeCodeFromHighlighter } from 'fumadocs-core/mdx-plugins/rehype-code.core';
import { highlighter } from './lib/highlighter';

export default defineConfig({
  mdxOptions: {
    // disable the default Shiki plugin
    rehypeCodeOptions: false,
    rehypePlugins: (v) => [
      [
        rehypeCodeFromHighlighter,
        // created with the transformers of Fumadocs, like notations and icons
        ({ transformers }) => highlighter.override({ shikiTransformers: transformers }),
      ],
      ...v,
    ],
  },
});

Integrations take it in their main entry:

IntegrationOption
SätterirehypeCodeFromHighlighter() from @fumadocs/satteri/rehype-code in hastPlugins
Python, Local HTMLcreatePython({ highlighter }), localHtml({ highlighter })
OpenAPI, GraphQL, AsyncAPIcreateOpenAPIPage({ highlighter })
Type TableremarkAutoTypeTable({ highlighter }), <AutoTypeTable highlighter />
shadcncreateSnippet({ highlighter }) from @fumadocs/shadcn/rsc

Where Fumadocs adds transformers to code blocks, like rehypeCodeFromHighlighter() and the ones of Python, Local HTML and shadcn, a function receives them.

Shiki Factory

Fumadocs manages Shiki instances with Shiki factories, you can create one for special purposes like using fine-grained bundles:

import { createShikiFactory } from 'fumadocs-core/highlight/shiki';

export const myShikiFactory = createShikiFactory({
  async init(options) {
    const { createHighlighter, createJavaScriptRegexEngine } = await import('shiki');

    return createHighlighter({
      langs: [],
      themes: [],
      langAlias: options?.langAlias,
      engine: createJavaScriptRegexEngine(),
    });
  },
});

Then pass it to different modules/features:

'use client';
import * as Base from 'fumadocs-ui/components/dynamic-codeblock.core';

export type DynamicCodeblockProps = Omit<Base.DynamicCodeblockProps, 'highlighter'>;

export function DynamicCodeBlock(props: DynamicCodeblockProps) {
  return <Base.DynamicCodeBlock highlighter={() => myShikiFactory.getOrInit()} {...props} />;
}

Custom Highlighter

Implement the Highlighter interface:

import type { Highlighter } from 'fumadocs-core/highlight';

export const highlighter: Highlighter = {
  codeToHast(code, { lang, structure, meta }) {
    // return `pre > code > span.line` with `meta` on `<pre>`, or the content of `<code>` when `structure` is `inline`
  },
  // optional, for languages loaded on demand
  async loadLanguage(...langs) {},
};

Fumadocs UI colors the tokens with CSS variables like --shiki-light and --shiki-dark. Pass it like other highlighters, or highlight a rehype pipeline of your own with rehypeCodeFromHighlighter:

import { rehypeCodeFromHighlighter } from 'fumadocs-core/mdx-plugins/rehype-code.core';

unified().use(rehypeCodeFromHighlighter, highlighter);

How is this guide?

Last updated on