Color mode

D2

D2 diagram rendering for ```d2 code blocks.

日本語

Overview

d2() replaces D2 code blocks with a <figure class="rb-d2"> that renders to SVG. Diagrams are rendered at build time by the D2 WebAssembly engine running in Node, with an automatic client-side fallback. It runs with order: -10.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { d2 } from "@riebeckite/plugin-d2";
 
export default defineConfig({
  // ...
  plugins: [
    d2({
      render: "build",
      theme: { light: 0, dark: 1 },
      layout: "dagre",
    }),
  ],
});

Syntax

markdown
```d2 title="Request flow"
client -> server: request
server -> database: query
```

A caption can also be written as the first line of the block. D2 uses # for comments, so a leading # caption: ... line is treated as a caption and removed before rendering:

markdown
```d2
# caption: Request flow
client -> server: request
```

Behavior

Build

  • Replaces each ```d2 <pre> with a figure.rb-d2 containing:
    • figcaption.rb-d2__caption — from the code block title or a # caption: ... line
    • div.rb-d2__canvas — the diagram (role="img", labelled by the caption when present)
    • details.rb-d2__fallback — collapsible diagram source
  • Static SVG is rendered at build time when render is "build" or "both" by running the D2.js WebAssembly engine (@d2lang/d2) directly in Node. No browser, network access, or system D2 binary is required.
  • The generated figure always carries data-d2, data-d2-source, and data-d2-layout attributes. data-d2 is rendered when static SVG is present and pending when the client must take over.
  • Invalid diagrams report ruleId: "invalid-diagram"; renderer failures report ruleId: "renderer-error". When build SVG is unavailable, the figure remains data-d2="pending" for client fallback.

Client (initD2Diagrams)

  • Loads D2.js as an ESM module from jsDelivr unless globalThis.d2 or an injected module is provided
  • Renders every [data-d2="pending"] figure; failures set data-d2="error" (placeholder message via CSS)
  • When theme is { light, dark }, the theme is chosen from html[data-theme] or prefers-color-scheme

Options

Option Type Default Description
render "build" | "client" | "both" "build" When diagrams are rendered
theme number | { light: number; dark: number } { light: 0, dark: 1 } D2 theme id(s)
layout "dagre" | "elk" "dagre" D2 layout engine
caption boolean true Show title / # caption: as figcaption
fallback boolean true Show the diagram source in <details>
className string "rb-d2" Base CSS class for the figure

render modes:

  • "build" — render SVG at build time; diagrams that fail fall back to client rendering
  • "client" — skip build-time rendering, render in the browser only
  • "both" — compatibility alias. It currently behaves like "build": build first, then client fallback only when build rendering fails

Offline requirements

Build-time rendering is fully offline: @d2lang/d2 ships a WebAssembly build that is loaded from node_modules. Client rendering (render: "client" or a build failure) downloads D2.js from jsDelivr; point moduleUrl at a self-hosted copy if the deployment has no outbound network access.

Output hooks

  • Set globalThis.d2 to a preloaded D2.js module to skip the CDN import.
  • Pass api and moduleUrl to initD2Diagrams() when calling it directly.

Exports

  • d2(options?) — plugin factory (d2Plugin is an alias)
  • initD2Diagrams — client initializer
  • Types: D2Options, D2ClientOptions, D2RenderMode, D2Layout, D2Theme, D2ModuleApi

Limitations

  • A diagram is rendered per build with a fresh D2 worker; very large batches pay the WASM startup cost repeatedly.
  • layout: "elk" uses D2's ELK engine, which is slower than dagre.
  • Multi-board and animated D2 output are not configured by this plugin.
  • The renderer is @d2lang/d2 (MPL-2.0), the current package for the D2.js WASM build; @terrastruct/d2 is its compatibility alias.

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/d2/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # D2
4 +
5 + D2 diagram rendering for ` ```d2 ` code blocks.
6 +
7 + [日本語](./d2.md)
8 +
9 + ## Overview
10 +
11 + `d2()` replaces D2 code blocks with a `<figure class="rb-d2">` that renders to
12 + SVG. Diagrams are rendered at build time by the D2 WebAssembly engine running in
13 + Node, with an automatic client-side fallback. It runs with `order: -10`.
14 +
15 + ## Usage
16 +
17 + ```ts
18 + import { defineConfig } from "@riebeckite/core";
19 + import { d2 } from "@riebeckite/plugin-d2";
20 +
21 + export default defineConfig({
22 + // ...
23 + plugins: [
24 + d2({
25 + render: "build",
26 + theme: { light: 0, dark: 1 },
27 + layout: "dagre",
28 + }),
29 + ],
30 + });
31 + ```
32 +
33 + ## Syntax
34 +
35 + ````markdown
36 + ```d2 title="Request flow"
37 + client -> server: request
38 + server -> database: query
39 + ```
40 + ````
41 +
42 + A caption can also be written as the first line of the block. D2 uses `#` for
43 + comments, so a leading `# caption: ...` line is treated as a caption and removed
44 + before rendering:
45 +
46 + ````markdown
47 + ```d2
48 + # caption: Request flow
49 + client -> server: request
50 + ```
51 + ````
52 +
53 + ## Behavior
54 +
55 + ### Build
56 +
57 + - Replaces each ` ```d2 ` `<pre>` with a `figure.rb-d2` containing:
58 + - `figcaption.rb-d2__caption` — from the code block title or a
59 + `# caption: ...` line
60 + - `div.rb-d2__canvas` — the diagram (`role="img"`, labelled by the caption
61 + when present)
62 + - `details.rb-d2__fallback` — collapsible diagram source
63 + - Static SVG is rendered at build time when `render` is `"build"` or `"both"`
64 + by running the D2.js WebAssembly engine (`@d2lang/d2`) directly in Node. No
65 + browser, network access, or system D2 binary is required.
66 + - The generated figure always carries `data-d2`, `data-d2-source`, and
67 + `data-d2-layout` attributes. `data-d2` is `rendered` when static SVG is
68 + present and `pending` when the client must take over.
69 + - Invalid diagrams report `ruleId: "invalid-diagram"`; renderer failures report
70 + `ruleId: "renderer-error"`. When build SVG is unavailable, the figure remains
71 + `data-d2="pending"` for client fallback.
72 +
73 + ### Client (`initD2Diagrams`)
74 +
75 + - Loads D2.js as an ESM module from jsDelivr unless `globalThis.d2` or an
76 + injected module is provided
77 + - Renders every `[data-d2="pending"]` figure; failures set `data-d2="error"`
78 + (placeholder message via CSS)
79 + - When `theme` is `{ light, dark }`, the theme is chosen from
80 + `html[data-theme]` or `prefers-color-scheme`
81 +
82 + ## Options
83 +
84 + | Option | Type | Default | Description |
85 + | ------ | ---- | ------- | ----------- |
86 + | `render` | `"build" \| "client" \| "both"` | `"build"` | When diagrams are rendered |
87 + | `theme` | `number \| { light: number; dark: number }` | `{ light: 0, dark: 1 }` | D2 theme id(s) |
88 + | `layout` | `"dagre" \| "elk"` | `"dagre"` | D2 layout engine |
89 + | `caption` | `boolean` | `true` | Show title / `# caption:` as `figcaption` |
90 + | `fallback` | `boolean` | `true` | Show the diagram source in `<details>` |
91 + | `className` | `string` | `"rb-d2"` | Base CSS class for the figure |
92 +
93 + `render` modes:
94 +
95 + - `"build"` — render SVG at build time; diagrams that fail fall back to client
96 + rendering
97 + - `"client"` — skip build-time rendering, render in the browser only
98 + - `"both"` — compatibility alias. It currently behaves like `"build"`: build
99 + first, then client fallback only when build rendering fails
100 +
101 + ## Offline requirements
102 +
103 + Build-time rendering is fully offline: `@d2lang/d2` ships a WebAssembly build
104 + that is loaded from `node_modules`. Client rendering (`render: "client"` or a
105 + build failure) downloads D2.js from jsDelivr; point `moduleUrl` at a self-hosted
106 + copy if the deployment has no outbound network access.
107 +
108 + ## Output hooks
109 +
110 + - Set `globalThis.d2` to a preloaded D2.js module to skip the CDN import.
111 + - Pass `api` and `moduleUrl` to `initD2Diagrams()` when calling it directly.
112 +
113 + ## Exports
114 +
115 + - `d2(options?)` — plugin factory (`d2Plugin` is an alias)
116 + - `initD2Diagrams` — client initializer
117 + - Types: `D2Options`, `D2ClientOptions`, `D2RenderMode`, `D2Layout`, `D2Theme`,
118 + `D2ModuleApi`
119 +
120 + ## Limitations
121 +
122 + - A diagram is rendered per build with a fresh D2 worker; very large batches pay
123 + the WASM startup cost repeatedly.
124 + - `layout: "elk"` uses D2's ELK engine, which is slower than `dagre`.
125 + - Multi-board and animated D2 output are not configured by this plugin.
126 + - The renderer is `@d2lang/d2` (MPL-2.0), the current package for the D2.js WASM
127 + build; `@terrastruct/d2` is its compatibility alias.
128 +
129 + ## See also
130 +
131 + - [Plugin guide](../reference/plugin-api.en.md)
132 +