A table of contents, usually headed simply Contents and abbreviated informally as TOC, is a list, usually found on a page before the start of a written work, of its chapter or section titles or brief descriptions with their commencing page numbers. Wikipedia
The plugin works particularly well with markdown documents.
By defaults
Before:
<html>
<body>
<h1 id="title1">Title 1</h1>
<p>p1</p>
<h2 id="title2">Title 2</h2>
<p>p2</p>
<h3 id="title3">Title 3</h3>
<p>p3</p>
</body>
</html>
After:
<html>
<body>
<h1 id="title1">Title 1</h1>
<div id="toc">
<div id="toctitle">Contents</div>
<ul>
<li>
<a href="#title2">Title 2</a>
<ul>
<li><a href="#title3">Title 3</a></li>
</ul>
</li>
</ul>
</div>
<p>p1</p>
<h2 id="title2">Title 2</h2>
<p>p2</p>
<h3 id="title3">Title 3</h3>
<p>p3</p>
</body>
</html>
Installation in your project
npm i posthtml posthtml-toc
const fs = require('fs');
const posthtml = require('posthtml');
const toc = require('posthtml-toc');
posthtml()
.use(toc({ /* options */ }))
.process(html/*, options */)
.then(result => fs.writeFileSync('./after.html', result.html));
Defaults options
insert = { after: 'h1' }
— insert the TOC immediately after the first<h1>
title = "Content"
— Title TOC blockignoreMissingSelector = false
— throw an error if the selector is not foundignoreMissingHeadings = false
— throw an error if the no headings are foundtoggle
is undefined
This option allows you to specify where the TOC will be inserted in the HTML output. The option expects an object with exactly one key with a string value, as in this schema:
{ insert: { <position>: <selector> } }
<selector>
is a string used to select an HTML element by matching one of three
patterns:
-
'<tag>'
— matches the first element with the name<tag>
.Example:
'nav'
matches<nav>
. -
'#<id>'
— matches the first element with<id>
as theid
attribute value.Example:
'#here'
matches<div id="here">
. -
'.<class>'
— matches the first element with<class>
as one of the space-separated strings in theclass
attribute value.Example:
'.here'
matches<div class="are you here or there">
.
<position>
can be one of the following:
-
after
— The TOC will be inserted immediately after the matching node.Example:
{ insert: { after: 'h1' } }
(default) produces:<h1>...</h1> +<div id="toc">...</div> <p>...</p>
-
before
— The TOC will be inserted immediately before the matching node.Example:
{ insert: { before: '#here' } }
produces:<p>...</p> +<div id="toc">...</div> <div id="here">...</div>
-
afterChildren
— The TOC will be inserted into the contents of the matching node after the last child.Example:
{ insert: { afterChildren: '.here' } }
produces:<nav class="here"> <p>...</p> + <div id="toc">...</div> </nav>
-
beforeChildren
— The TOC will be inserted into the contents of the matching node before the first child.Example:
{ insert: { beforeChildren: '.here' } }
produces:<nav class="here"> + <div id="toc">...</div> <p>...</p> </nav>
Before:
<html>
<body>
<h1 id="title1">Title 1</h1>
<p>p1</p>
<h2 id="title2">Title 2</h2>
<p>p2</p>
<h3 id="title3">Title 3</h3>
<p>p3</p>
</body>
</html>
Add option:
const fs = require('fs');
const posthtml = require('posthtml');
const toc = require('posthtml-toc');
posthtml()
.use(toc({
toggle: ['show', 'hide', true]
}))
.process(html/*, options */)
.then(result => fs.writeFileSync('./after.html', result.html));
After:
<html>
<body>
<h1 id="title1">Title 1</h1>
<style>
#toctoggle,#toctoggle:checked~ul{display:none}
#toctoggle~label:after{content:"hide"}
#toctoggle:checked~label:after{content:"show"}
#toc label{cursor:pointer}
</style>
<div id="toc">
<input type="checkbox" role="button" id="toctoggle" checked>
<h2>Content</h2>
<label for="toctoggle"></label>
<ul>
<li>
<a href="#title2">Title 2</a>
<ul>
<li><a href="#title3">Title 3</a></li>
</ul>
</li>
</ul>
</div>
<p>p1</p>
<h2 id="title2">Title 2</h2>
<p>p2</p>
<h3 id="title3">Title 3</h3>
<p>p3</p>
</body>
</html>
-
{ ignoreMissingSelector: false }
(default) — throw an error if the selector (the defaulth1
tag or the value passed tooptions.after
) is not found.For example, with this option, you get an error on the second file because there is no
h1
tag:<!-- file-with-toc.html --> <h1>Title 1</h1> <h2 id="title2">Title 2</h2>
<!-- file-without-toc.html --> <div></div>
-
{ ignoreMissingSelector: true }
— ignore HTML input that does not have the selector.This is useful if you want to uniformly process a number of files but don't want to insert a TOC in all of them.
For example, with the files mentioned above, instead of an error, the first file is modified and the second file is unchanged:
<!-- file-with-toc.html --> <h1>Title 1</h1> <div id="toc"><h2>Content</h2><ul><li><a href="#title2">Title 2</a></li></ul></div> <h2 id="title2">Title 2</h2>
<!-- file-without-toc.html --> <div></div>
This option controls what happens when no headings (h2
, h3
, h4
, h5
,
h6
) are found in the HTML input.
-
{ ignoreMissingHeadings: false }
(default) — throw an error if no headings are found. -
{ ignoreMissingHeadings: true }
— do not throw an error if no headings are found. Instead, a TOC with an empty list (i.e.<ul></ul>
) will be inserted.
See PostHTML Guidelines and contribution guide.