fumadocs-dgmo
v0.3.4
Published
Fumadocs integration to render DGMO diagrams from fenced code blocks at build time. Two-step install: `withDgmo()` in source.config.ts plus `<DgmoClient />` in app/layout.tsx — the client component handles route-change rebinding and auto-imports the theme
Maintainers
Readme
fumadocs-dgmo
Render DGMO diagrams from ```dgmo fenced code blocks in your Fumadocs site at build time. Powered by @diagrammo/dgmo and the framework-agnostic remark-dgmo core. Zero client JavaScript by default (one tiny re-binder fires on route change).
Every diagram is rendered twice at build time (light + dark palettes) and follows Fumadocs UI's color-mode toggle through a shipped, .dark-rewritten stylesheet.
Install
pnpm add fumadocs-dgmo @diagrammo/dgmo@diagrammo/dgmo, fumadocs-mdx, next, and react are peer dependencies. Node 20.6+.
Quick start
Two small edits to your Fumadocs site.
1. source.config.ts — wire the remark plugin
import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
import { withDgmo } from 'fumadocs-dgmo/config';
export default defineConfig({
mdxOptions: withDgmo(),
});
export const docs = defineDocs({
dir: 'content/docs',
});withDgmo() augments your mdxOptions.remarkPlugins with remark-dgmo and defaults mdx: true on it so blocks render as MDX-safe mdxJsxFlowElement nodes. Idempotent. If you already have your own remark plugins, pass the existing mdxOptions object in:
mdxOptions: withDgmo({ remarkPlugins: [myOtherPlugin] }),remark-dgmo is prepended so it runs before any downstream remark plugin.
2. app/layout.tsx — mount the client component
import './global.css';
import { RootProvider } from 'fumadocs-ui/provider';
import { DgmoClient } from 'fumadocs-dgmo/client';
import type { ReactNode } from 'react';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<RootProvider>
{children}
<DgmoClient />
</RootProvider>
</body>
</html>
);
}<DgmoClient /> is a no-render Client Component that does two things:
- Runs
bindDgmo()on initial mount and on every soft route change — Next's app router doesn't refireDOMContentLoadedsemantics on client-side navigation, so without this you'd lose viewBox tightening and showcase-mode copy buttons after the first SPA transition. - Side-effect-imports the shipped
fumadocs-dgmo/client.cssso Next's CSS pipeline picks it up automatically. The stylesheet is generated fromremark-dgmo/client.cssat build time with[data-theme="dark"]rewritten tohtml.dark— the attribute Fumadocs UI'snext-themesdefault uses. No manual@importrequired.
That's the whole integration.
Passing remark-dgmo options
mdxOptions: withDgmo({}, { dgmo: { palette: 'catppuccin', colorMode: 'auto' } }),The second argument forwards anything in remark-dgmo's option surface (palette, theme, colorMode, mode, className, etc.).
Configure (manual)
If withDgmo doesn't fit (dynamic remark plugin loading, you need to inspect the wiring), do it by hand:
import { defineConfig } from 'fumadocs-mdx/config';
import remarkDgmo from 'fumadocs-dgmo/remark';
export default defineConfig({
mdxOptions: {
remarkPlugins: [[remarkDgmo, { mdx: true }]],
},
});The mdx: true option is required — Fumadocs always routes content through @mdx-js/mdx, which rejects the raw html mdast nodes remark-dgmo emits by default.
Use
Drop a fenced block with the language dgmo into any .md/.mdx file under your content/docs/ directory.
```dgmo
sequence
Client -POST /login-> API
API -validate-> Auth
Auth -JWT-> API
API -200 OK-> Client
```Per-block overrides
Append options to the fence info string. Tokens are space-separated; values may be quoted.
```dgmo showcase title="Login flow" palette=catppuccin colorMode=light
sequence
A -> B
```See the remark-dgmo README for the full option matrix.
Working reference site
tests/fixture/ is a complete minimal Fumadocs site running this wrapper. Copy tests/fixture/source.config.ts and tests/fixture/app/layout.tsx as templates for your own site.
git clone https://github.com/diagrammo/fumadocs-dgmo
cd fumadocs-dgmo
pnpm install && pnpm build
cd tests/fixture && pnpm install --no-frozen-lockfile && pnpm devOpens at http://localhost:3000. Navigate to /docs/diagrams for four example diagrams (plain auto, colored tag sequence, showcase mode, per-block override). The fixture's package.json scripts pin Next 16 to webpack (--webpack) because Turbopack 16.2.x can't resolve a pnpm link: dep's exports-map subpath; consumers installing from npm aren't affected. See tests/fixture/README.md for details.
How CSS is delivered
fumadocs-dgmo/client.css is the shipped stylesheet. It's the same three visibility rules + sizing + showcase chrome as upstream remark-dgmo/client.css, but the dark-mode selector is rewritten from [data-theme="dark"] to html.dark — the attribute Fumadocs UI's next-themes integration uses by default.
It's auto-imported by <DgmoClient /> via a side-effect import 'fumadocs-dgmo/client.css'. Next's CSS pipeline picks the import up from the Client Component module and extracts it into the page bundle. If you prefer to manage the import yourself, drop in the manual config path below and @import 'fumadocs-dgmo/client.css' from your app/global.css instead.
Custom color-mode selector
If you've configured next-themes with a non-default attribute (e.g. attribute="data-theme"), the shipped CSS won't match. Two options:
- Switch back to the default (Fumadocs UI's preset CSS expects
html.dark). - Skip
<DgmoClient />'s auto-import and instead@import 'remark-dgmo/client.css'directly inapp/global.css(keys on[data-theme="dark"]), then override the Fumadocs UI preset's dark-mode rules to match. This is uncommon and usually means the host site is fighting Fumadocs UI rather than this wrapper.
See the "Custom color-mode selector" section in the remark-dgmo README for the underlying selectors.
How it works
withDgmoprependsremark-dgmo(withmdx: true) to yourmdxOptions.remarkPluginsarray.fumadocs-mdx's build pipeline runs the plugin during MDX compilation.- For each fenced
dgmoblock,remark-dgmocallsrender()from@diagrammo/dgmoonce per theme (under defaultcolorMode: 'auto') and replaces the block with anmdxJsxFlowElementcarrying the rendered SVG wrappers viadangerouslySetInnerHTML. - The shipped CSS, side-effect-imported by
<DgmoClient />, gates the wrappers' visibility onhtml.dark. Toggling Fumadocs UI's theme switcher flips the class, which flips visibility. - The
<DgmoClient />Client Component subscribes tousePathname()and re-runsbindDgmo()on every soft navigation. The function tightens each diagram'sviewBoxto content bounds and wires showcase-mode copy buttons.
All rendering happens at build time. The browser ships only inline SVG + the small CSS rules + a ~1.5 KB bindDgmo payload.
License
MIT
