remark plugin that turns markdown into HTML to support rehype
npx @tessl/cli install tessl/npm-remark-rehype@11.1.00
# remark-rehype
1
2
remark-rehype is a unified plugin that bridges the markdown ecosystem (remark/mdast) and the HTML ecosystem (rehype/hast). It transforms markdown syntax trees into HTML syntax trees, enabling users to process markdown with remark plugins and then continue processing the resulting HTML with rehype plugins.
3
4
## Package Information
5
6
- **Package Name**: remark-rehype
7
- **Package Type**: npm
8
- **Language**: TypeScript (compiled to JavaScript)
9
- **Installation**: `npm install remark-rehype`
10
11
## Core Imports
12
13
```javascript
14
import remarkRehype from "remark-rehype";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const remarkRehype = require("remark-rehype");
21
```
22
23
Re-exported utilities from mdast-util-to-hast:
24
25
```javascript
26
import {
27
defaultFootnoteBackContent,
28
defaultFootnoteBackLabel,
29
defaultHandlers
30
} from "remark-rehype";
31
```
32
33
## Basic Usage
34
35
```javascript
36
import { unified } from "unified";
37
import remarkParse from "remark-parse";
38
import remarkRehype from "remark-rehype";
39
import rehypeStringify from "rehype-stringify";
40
41
// Basic markdown to HTML transformation
42
const file = await unified()
43
.use(remarkParse) // Parse markdown
44
.use(remarkRehype) // Transform to HTML
45
.use(rehypeStringify) // Serialize HTML
46
.process("# Hello World"); // Process markdown
47
48
console.log(String(file)); // "<h1>Hello World</h1>"
49
```
50
51
## Architecture
52
53
remark-rehype operates in two distinct modes:
54
55
- **Mutate Mode** (default): Returns a hast tree that can be processed by subsequent rehype plugins
56
- **Bridge Mode**: Runs a provided processor with the hast tree, then discards the result and continues with the original mdast tree
57
58
The plugin relies on `mdast-util-to-hast` for the core transformation logic and provides unified plugin integration with comprehensive options for customization.
59
60
## Capabilities
61
62
### Plugin Function
63
64
The main plugin function that transforms markdown (mdast) syntax trees into HTML (hast) syntax trees.
65
66
```typescript { .api }
67
/**
68
* Turn markdown into HTML.
69
*
70
* @param destination - Processor for bridge mode, or options for mutate mode
71
* @param options - Configuration options when processor is provided
72
* @returns Transform function for the unified pipeline
73
*/
74
function remarkRehype(
75
destination?: Processor | Options,
76
options?: Options
77
): TransformMutate | TransformBridge;
78
79
// Mutate mode - returns hast tree for further processing
80
type TransformMutate = (tree: MdastRoot, file: VFile) => HastRoot;
81
82
// Bridge mode - runs processor and discards result
83
type TransformBridge = (tree: MdastRoot, file: VFile) => Promise<undefined>;
84
```
85
86
**Usage Examples:**
87
88
```javascript
89
import { unified } from "unified";
90
import remarkParse from "remark-parse";
91
import remarkRehype from "remark-rehype";
92
import rehypeStringify from "rehype-stringify";
93
94
// Mutate mode (default)
95
const processor = unified()
96
.use(remarkParse)
97
.use(remarkRehype)
98
.use(rehypeStringify);
99
100
// Mutate mode with options
101
const processorWithOptions = unified()
102
.use(remarkParse)
103
.use(remarkRehype, {
104
allowDangerousHtml: true,
105
handlers: { /* custom handlers */ }
106
})
107
.use(rehypeStringify);
108
109
// Bridge mode
110
const bridgeProcessor = unified()
111
.use(remarkParse)
112
.use(remarkRehype, unified().use(rehypeStringify))
113
.use(remarkStringify); // Continue with markdown processing
114
```
115
116
### Configuration Options
117
118
Comprehensive configuration options for customizing the transformation behavior.
119
120
```typescript { .api }
121
interface Options {
122
/** Allow raw HTML in markdown to be passed through */
123
allowDangerousHtml?: boolean;
124
125
/** Custom handlers for specific node types */
126
handlers?: Partial<Record<string, Handler>>;
127
128
/** Node types to pass through unchanged */
129
passThrough?: string[];
130
131
/** Handler for unknown node types */
132
unknownHandler?: Handler;
133
134
/** Function to generate footnote back-reference labels */
135
footnoteBackLabel?: (referenceIndex: number, rereferenceIndex: number) => string;
136
137
/** Function to generate footnote back-reference content */
138
footnoteBackContent?: (referenceIndex: number, rereferenceIndex: number) => ElementContent[];
139
140
/** Label to use for the footnotes section (affects screen readers) */
141
footnoteLabel?: string;
142
143
/** Properties for footnote label elements */
144
footnoteLabelProperties?: Properties;
145
146
/** Tag name for footnote label elements */
147
footnoteLabelTagName?: string;
148
149
/** Prefix for DOM clobbering prevention */
150
clobberPrefix?: string;
151
}
152
153
type Handler = (state: State, node: Node) => Element | ElementContent[] | void;
154
```
155
156
**Usage Examples:**
157
158
```javascript
159
// Custom footnote labels for non-English languages
160
const germanOptions = {
161
footnoteBackLabel(referenceIndex, rereferenceIndex) {
162
return 'Zurück zu Referenz ' + (referenceIndex + 1) +
163
(rereferenceIndex > 1 ? '-' + rereferenceIndex : '');
164
}
165
};
166
167
// Allow raw HTML processing
168
const htmlOptions = {
169
allowDangerousHtml: true
170
};
171
172
// Custom node handlers
173
const customOptions = {
174
handlers: {
175
// Override heading transformation
176
heading(state, node) {
177
return {
178
type: 'element',
179
tagName: 'h' + node.depth,
180
properties: { className: ['custom-heading'] },
181
children: state.all(node)
182
};
183
}
184
}
185
};
186
```
187
188
### Footnote Utilities
189
190
Pre-built utilities for GitHub-compatible footnote handling.
191
192
```typescript { .api }
193
/**
194
* Generate default content for footnote back-references
195
* @param referenceIndex - Index of the definition's first reference (0-indexed)
196
* @param rereferenceIndex - Index of calls to the same definition (0-indexed)
197
* @returns Array of hast element content nodes
198
*/
199
function defaultFootnoteBackContent(
200
referenceIndex: number,
201
rereferenceIndex: number
202
): ElementContent[];
203
204
/**
205
* Generate default accessibility labels for footnote back-references
206
* @param referenceIndex - Index of the definition's first reference (0-indexed)
207
* @param rereferenceIndex - Index of calls to the same definition (0-indexed)
208
* @returns Label string for screen readers
209
*/
210
function defaultFootnoteBackLabel(
211
referenceIndex: number,
212
rereferenceIndex: number
213
): string;
214
```
215
216
**Usage Examples:**
217
218
```javascript
219
import { defaultFootnoteBackContent, defaultFootnoteBackLabel } from "remark-rehype";
220
221
// Use default functions as templates for customization
222
function customFootnoteBackContent(refIndex, rerefIndex) {
223
const defaultContent = defaultFootnoteBackContent(refIndex, rerefIndex);
224
// Modify the default content as needed
225
return defaultContent;
226
}
227
228
// Check what the defaults generate
229
console.log(defaultFootnoteBackLabel(0, 1)); // "Back to reference 1"
230
console.log(defaultFootnoteBackLabel(1, 2)); // "Back to reference 2-2"
231
```
232
233
### Default Node Handlers
234
235
Complete set of default handlers for transforming all standard markdown node types to HTML.
236
237
```typescript { .api }
238
/**
239
* Default handlers for transforming mdast nodes to hast nodes
240
* Includes handlers for all standard CommonMark and GFM node types
241
*/
242
const defaultHandlers: Partial<Record<string, Handler>>;
243
```
244
245
**Available Handlers:**
246
- `blockquote` - Block quotes (`> text`)
247
- `break` - Hard line breaks (` \n`)
248
- `code` - Code blocks (` ``` `)
249
- `delete` - Strikethrough text (`~~text~~`)
250
- `emphasis` - Italic text (`*text*`)
251
- `footnoteReference` - Footnote references (`[^ref]`)
252
- `heading` - Headings (`# text`)
253
- `html` - Raw HTML
254
- `image` - Images (``)
255
- `imageReference` - Image references (`![alt][ref]`)
256
- `inlineCode` - Inline code (`` `code` ``)
257
- `link` - Links (`[text](url)`)
258
- `linkReference` - Link references (`[text][ref]`)
259
- `list` - Lists (`- item`)
260
- `listItem` - List items
261
- `paragraph` - Paragraphs
262
- `root` - Document root
263
- `strong` - Bold text (`**text**`)
264
- `table` - Tables
265
- `tableCell` - Table cells
266
- `tableRow` - Table rows
267
- `text` - Plain text
268
- `thematicBreak` - Horizontal rules (`---`)
269
270
**Usage Examples:**
271
272
```javascript
273
import { defaultHandlers } from "remark-rehype";
274
275
// Extend default handlers with custom ones
276
const customHandlers = {
277
...defaultHandlers,
278
heading(state, node) {
279
const result = defaultHandlers.heading(state, node);
280
// Add custom attributes to all headings
281
if (result && result.properties) {
282
result.properties.className = ['custom-heading'];
283
}
284
return result;
285
},
286
customNode(state, node) {
287
// Handle custom node types
288
return {
289
type: 'element',
290
tagName: 'div',
291
properties: { className: ['custom-node'] },
292
children: state.all(node)
293
};
294
}
295
};
296
297
const processor = unified()
298
.use(remarkParse)
299
.use(remarkRehype, { handlers: customHandlers })
300
.use(rehypeStringify);
301
```
302
303
## Types
304
305
```typescript { .api }
306
import type { Root as MdastRoot, Node as MdastNode } from "mdast";
307
import type { Root as HastRoot, Element, ElementContent, Properties } from "hast";
308
import type { VFile } from "vfile";
309
import type { Processor } from "unified";
310
import type { State } from "mdast-util-to-hast";
311
312
interface Options {
313
allowDangerousHtml?: boolean;
314
handlers?: Partial<Record<string, Handler>>;
315
passThrough?: string[];
316
unknownHandler?: Handler;
317
footnoteBackLabel?: (referenceIndex: number, rereferenceIndex: number) => string;
318
footnoteBackContent?: (referenceIndex: number, rereferenceIndex: number) => ElementContent[];
319
footnoteLabel?: string;
320
footnoteLabelProperties?: Properties;
321
footnoteLabelTagName?: string;
322
clobberPrefix?: string;
323
}
324
325
type Handler = (state: State, node: MdastNode) => Element | ElementContent[] | void;
326
327
type TransformMutate = (tree: MdastRoot, file: VFile) => HastRoot;
328
type TransformBridge = (tree: MdastRoot, file: VFile) => Promise<undefined>;
329
```
330
331
## Error Handling
332
333
The plugin handles several edge cases and error conditions:
334
335
- **Unknown Node Types**: Uses `unknownHandler` or falls back to creating `<div>` elements
336
- **Raw HTML**: Requires `allowDangerousHtml: true` option to process embedded HTML
337
- **DOM Clobbering**: Uses `clobberPrefix` to prevent ID-based security issues with footnotes
338
- **Invalid Footnotes**: Gracefully handles malformed footnote references and definitions
339
340
## Common Patterns
341
342
### Processing Raw HTML
343
344
```javascript
345
// Enable raw HTML processing (use with caution)
346
const processor = unified()
347
.use(remarkParse)
348
.use(remarkRehype, { allowDangerousHtml: true })
349
.use(rehypeRaw) // Parse raw HTML into proper hast nodes
350
.use(rehypeStringify);
351
```
352
353
### Multi-language Footnotes
354
355
```javascript
356
// Customize footnote labels for different languages
357
const frenchProcessor = unified()
358
.use(remarkParse)
359
.use(remarkRehype, {
360
footnoteBackLabel(refIndex) {
361
return `Retour à la référence ${refIndex + 1}`;
362
}
363
})
364
.use(rehypeStringify);
365
```
366
367
### Custom Node Processing
368
369
```javascript
370
// Handle custom markdown extensions
371
const processor = unified()
372
.use(remarkParse)
373
.use(remarkRehype, {
374
handlers: {
375
// Handle custom admonition blocks
376
admonition(state, node) {
377
return {
378
type: 'element',
379
tagName: 'div',
380
properties: {
381
className: ['admonition', node.type]
382
},
383
children: state.all(node)
384
};
385
}
386
}
387
})
388
.use(rehypeStringify);
389
```