or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-remark-toc

remark plugin to generate a table of contents (TOC)

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/remark-toc@9.0.x

To install, run

npx @tessl/cli install tessl/npm-remark-toc@9.0.0

0

# remark-toc

1

2

remark-toc is a [remark](https://github.com/remarkjs/remark) plugin that automatically generates table of contents (TOC) for markdown documents. It searches for headings that match a configurable pattern (default: 'Contents' or 'TOC'), removes existing content under that heading, and replaces it with a nested list of links to all subsequent headings in the document.

3

4

## Package Information

5

6

- **Package Name**: remark-toc

7

- **Package Type**: npm

8

- **Language**: JavaScript (ESM only)

9

- **Installation**: `npm install remark-toc`

10

11

## Core Imports

12

13

```javascript

14

import remarkToc from 'remark-toc'

15

```

16

17

For Deno:

18

19

```javascript

20

import remarkToc from 'https://esm.sh/remark-toc@9'

21

```

22

23

## Basic Usage

24

25

```javascript

26

import {remark} from 'remark'

27

import remarkToc from 'remark-toc'

28

import {read} from 'to-vfile'

29

30

const file = await remark()

31

.use(remarkToc)

32

.process(await read('example.md'))

33

34

console.log(String(file))

35

```

36

37

**Input markdown:**

38

39

```markdown

40

# My Document

41

42

Intro content here.

43

44

## Contents

45

46

## Chapter 1

47

48

Content...

49

50

### Subsection

51

52

More content...

53

54

## Chapter 2

55

56

Final content...

57

```

58

59

**Output markdown:**

60

61

```markdown

62

# My Document

63

64

Intro content here.

65

66

## Contents

67

68

* [Chapter 1](#chapter-1)

69

* [Subsection](#subsection)

70

* [Chapter 2](#chapter-2)

71

72

## Chapter 1

73

74

Content...

75

76

### Subsection

77

78

More content...

79

80

## Chapter 2

81

82

Final content...

83

```

84

85

## Capabilities

86

87

### Table of Contents Generation

88

89

Generates a table of contents by finding a heading that matches a configurable pattern and replacing its content with a structured list of all subsequent headings.

90

91

```javascript { .api }

92

/**

93

* Generate a table of contents (TOC).

94

*

95

* Looks for the first heading matching options.heading (case insensitive),

96

* removes everything between it and an equal or higher next heading, and

97

* replaces that with a list representing the rest of the document structure,

98

* linking to all further headings.

99

*/

100

function remarkToc(options?: Readonly<Options> | null | undefined): Transform;

101

```

102

103

**Usage with options:**

104

105

```javascript

106

import {remark} from 'remark'

107

import remarkToc from 'remark-toc'

108

109

// Custom heading pattern

110

const processor = remark().use(remarkToc, {

111

heading: 'table of contents|overview',

112

maxDepth: 3,

113

tight: false,

114

ordered: true

115

})

116

```

117

118

**Advanced configuration:**

119

120

```javascript

121

import {remark} from 'remark'

122

import remarkToc from 'remark-toc'

123

124

const processor = remark().use(remarkToc, {

125

heading: 'structure',

126

minDepth: 2,

127

maxDepth: 3,

128

skip: 'example|notes?',

129

prefix: 'user-content-',

130

parents: ['listItem', 'root'],

131

tight: false,

132

ordered: true

133

})

134

```

135

136

## Configuration Options

137

138

```javascript { .api }

139

interface Options {

140

/**

141

* Heading to look for, wrapped in new RegExp('^(' + value + ')$', 'i')

142

* @default '(table[ -]of[ -])?contents?|toc'

143

*/

144

heading?: string;

145

146

/**

147

* Max heading depth to include in the table of contents

148

* This is inclusive: when set to 3, level three headings are included (###)

149

* @default 6

150

*/

151

maxDepth?: number;

152

153

/**

154

* Min heading depth to include in the table of contents

155

* This is inclusive: when set to 2, only level two headings and deeper are included (##, ###, etc.)

156

* @default 1

157

*/

158

minDepth?: number;

159

160

/**

161

* Headings to skip, wrapped in new RegExp('^(' + value + ')$', 'i')

162

* Any heading matching this expression will not be present in the table of contents

163

*/

164

skip?: string;

165

166

/**

167

* Allow headings to be children of certain node types

168

* @default tree (root node)

169

*/

170

parents?: Test;

171

172

/**

173

* Whether to compile list items tightly, otherwise space is added around items

174

* @default true

175

*/

176

tight?: boolean;

177

178

/**

179

* Whether to compile list items as an ordered list, otherwise they are unordered

180

* @default false

181

*/

182

ordered?: boolean;

183

184

/**

185

* Add a prefix to links to headings in the table of contents

186

* Useful when later going from markdown to HTML and sanitizing with rehype-sanitize

187

* @example 'user-content-'

188

*/

189

prefix?: string;

190

}

191

192

type Test = string | Function | Object | Array<string | Function | Object>;

193

194

type Transform = (tree: Root) => undefined;

195

196

interface Root {

197

type: 'root';

198

children: Array<any>;

199

}

200

```

201

202

## Examples

203

204

### Custom Heading Pattern

205

206

```javascript

207

import {remark} from 'remark'

208

import remarkToc from 'remark-toc'

209

210

const processor = remark().use(remarkToc, {

211

heading: 'structure'

212

})

213

```

214

215

Searches for headings containing "structure" (case-insensitive).

216

217

### Ordered, Loose List

218

219

```javascript

220

import {remark} from 'remark'

221

import remarkToc from 'remark-toc'

222

223

const processor = remark().use(remarkToc, {

224

ordered: true,

225

tight: false

226

})

227

```

228

229

Generates:

230

231

```markdown

232

1. [History](#history)

233

234

1. [Discovery](#discovery)

235

2. [Name and symbol](#name-and-symbol)

236

3. [Planet X disproved](#planet-x-disproved)

237

238

2. [Orbit](#orbit)

239

```

240

241

### Including and Excluding Headings

242

243

```javascript

244

import {remark} from 'remark'

245

import remarkToc from 'remark-toc'

246

247

const processor = remark().use(remarkToc, {

248

maxDepth: 3,

249

parents: ['listItem', 'root'],

250

skip: 'delta'

251

})

252

```

253

254

- Only includes level 1, 2, and 3 headings

255

- Allows headings directly in list items

256

- Excludes headings with text "delta" (case-insensitive, full match)

257

258

### Setting Heading Depth Range

259

260

```javascript

261

import {remark} from 'remark'

262

import remarkToc from 'remark-toc'

263

264

const processor = remark().use(remarkToc, {

265

minDepth: 2,

266

maxDepth: 4

267

})

268

```

269

270

- Only includes level 2, 3, and 4 headings (##, ###, ####)

271

- Excludes top-level headings (#) from the table of contents

272

- Useful when the main document title should not appear in the TOC

273

274

### Adding Link Prefix

275

276

```javascript

277

import {remark} from 'remark'

278

import remarkToc from 'remark-toc'

279

280

const processor = remark().use(remarkToc, {

281

prefix: 'user-content-'

282

})

283

```

284

285

Generates:

286

287

```markdown

288

* [History](#user-content-history)

289

* [Discovery](#user-content-discovery)

290

* [Name and symbol](#user-content-name-and-symbol)

291

* [Orbit](#user-content-orbit)

292

```

293

294

## Compatibility

295

296

- **Node.js**: Version 16+

297

- **unified**: Version 3+

298

- **remark**: Version 4+

299

- **Package Type**: ESM only

300

301

## Security Considerations

302

303

remark-toc copies existing nodes into the table of contents, which can include script tags or other HTML content. When transforming to HTML, ensure proper sanitization:

304

305

```markdown

306

# Contents

307

308

## Bravo<script>alert(1)</script>

309

```

310

311

Becomes:

312

313

```markdown

314

# Contents

315

316

- [Bravo<script>alert(1)</script>](#bravoscriptalert1script)

317

318

## Bravo<script>alert(1)</script>

319

```

320

321

Use [rehype-sanitize](https://github.com/rehypejs/rehype-sanitize) when converting to HTML.