Thanks to the Twoslash integration of Shiki, the default code syntax highlighter, it is as simple as adding a transformer.
npm install fumadocs-twoslash
Add to your Shiki transformers.
Example for Fumadocs MDX
import { defineConfig } from 'fumadocs-mdx/config';
import { transformerTwoslash } from 'fumadocs-twoslash';
import { rehypeCodeDefaultOptions } from 'fumadocs-core/mdx-plugins';
 
export default defineConfig({
  mdxOptions: {
    rehypeCodeOptions: {
      transformers: [
        ...(rehypeCodeDefaultOptions.transformers ?? []),
        transformerTwoslash(),
      ],
    },
  },
});
Add required styles and components, note that you have to configure Tailwind CSS and the official Tailwind CSS plugin first.
import 'fumadocs-twoslash/twoslash.css';
import { Popup, PopupContent, PopupTrigger } from 'fumadocs-twoslash/ui';
import defaultMdxComponents from 'fumadocs-ui/mdx';
 
<MDX
  components={{
    ...defaultMdxComponents,
    Popup,
    PopupContent,
    PopupTrigger,
  }}
/>;
Now you can add twoslash meta string to codeblocks.
```ts twoslash
console.log('Hello World');
```
Learn more about Twoslash notations.
console.g- group
- groupCollapsed
- groupEnd
;
 
 
 
 
 
const player: Player = { name: 'Hello World' };
const a = '123';
 
console.log(a);
 
import { generateFiles } from 'fumadocs-openapi';
 
void generateFiles({
  input: ['./museum.yaml'],
  output: './content/docs/ui',
});
const a = '123';
 
a = 132;Cannot assign to 'a' because it is a constant.
To use it on Next.js runtime, add typescript and twoslash to serverExternalPackages:
import { createMDX } from 'fumadocs-mdx/next';
 
const withMDX = createMDX();
 
/** @type {import('next').NextConfig} */
const config = {
  reactStrictMode: true,
  serverExternalPackages: ['twoslash', 'typescript'],
};
 
export default withMDX(config);
Install the external dependencies:
npm install typescript twoslash
Pass the transformer to Shiki, see https://shiki.style/packages/next for details.
import React from 'react';
import { CodeBlock, Pre } from 'fumadocs-ui/components/codeblock';
import { createStyleTransformer } from 'fumadocs-core/server';
import { transformerTwoslash } from 'fumadocs-twoslash';
import { Popup, PopupContent, PopupTrigger } from 'fumadocs-twoslash/ui';
import { getSingletonHighlighter, bundledLanguages } from 'shiki';
import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
import { Fragment, jsx, jsxs } from 'react/jsx-runtime';
 
export async function Code({
  code,
  lang = 'ts',
}: {
  lang?: string;
  code: string;
}) {
  const highlighter = await getSingletonHighlighter({
    langs: Object.keys(bundledLanguages),
    themes: ['vesper'],
  });
 
  const hast = highlighter.codeToHast(code, {
    lang,
    themes: {
      light: 'vesper',
      dark: 'vesper',
    },
    defaultColor: false,
    transformers: [
      createStyleTransformer(),
      transformerTwoslash({
        explicitTrigger: false,
      }),
    ],
  });
 
  const rendered = toJsxRuntime(hast, {
    Fragment,
    jsx,
    jsxs,
    development: false,
    components: {
      pre: (props) => (
        <CodeBlock {...props}>
          <Pre>{props.children}</Pre>
        </CodeBlock>
      ),
      // @ts-expect-error -- Twoslash components
      Popup,
      PopupContent,
      PopupTrigger,
    },
  });
 
  return rendered;
}