or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# 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 (`![alt](src)`)

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

```