[More quick guides]

A quick guide to
creating Table of Contents
in Prince 14

A script brings something to the table

Prince is a HTML-to-PDF-via-CSS converter which is often for creating books from HTML and CSS. Most books have a Table of Contents (ToC) to help readers navigate the content. In the ToC, headings appear alongside page numbers. Page numbers, however, must be calculated by the formatter, and not a human author. This guide will show you how to automatically generate a Table of Contents in your book.

Starting point

We start with a simple HTML document, which has a title page and two short chapters:

htmlh1, h2 { break-before: page }

<h1>Waterfowl</h1>
<h2>Ducks</h2> ...
<h2>Geese</h2> ...
...

There is no ToC in the above document. Let's add one!

Adding a ToC

Adding a ToC is easy – a script does most of the work. First, we add an empty element into which the ToC will be poured. A ToC is an ordered list, so we use the <ol> element for this:

<ol id=toc></ol>

Second, we must tell the script which elements should copied into the ToC. This is done by providing a CSS selector in a function call:

<script type="text/javascript" src="https://princexml.com/howcome/2021/guides/charms.js"></script>
<body onload="toc('h2')">

Third, we must add some lines of CSS to style the elements generated by the script:

#toc li { list-style-type: none }
#toc a:after { content: leader('. ') target-counter(attr(href), page) }

Adding these code snippets into our barebone example, we get:

htmlh1, h2 { break-before: page }
#toc li { list-style-type: none }
#toc a:after { content: leader('. ') target-counter(attr(href), page) }
...
<script type="text/javascript" src="https://princexml.com/howcome/2020/guides/charms.js">
<body onload="toc('h2')">
<h1>Waterfowl</h1>
<h2>Table of Contents</h2>
<ol id=toc></ol>
<h2>Ducks</h2> ...
<h2>Geese</h2> ...

The resulting ToC can be seen on page 2 above. Try clicking on the blue links in the PDF document!

Multi-level ToC

Textbooks and other complex documents often have multi-level chapter structures where CSS pseudo-elements are used to number chapters and sections. Here is an example which uses CSS counters to add numbering. Not all headlines should be numbered, though, therefore fancy :not selectors are used:

htmlh2:not(h2.toc) { 
  counter-increment: section; counter-reset: subsection 0 }
h2:not(h2.toc):before { 
  content: "Chapter " counter(section) ": " }

h3 { counter-increment: subsection }
h3::before { 
  content: counter(section) "." counter(subsection) ": " }
...
<script type="text/javascript" src="https://princexml.com/howcome/2021/guides/charms.js">
<body onload="toc('h2, h3')">
<h2>Table of Contents</h2>
<ol id=toc></ol>

<h1>Waterfowl</h1>
  <h2>Ducks</h2> ...
    <h3>Feet and feathers</h3> ...
    <h3>Habitat</h3> ...
  <h2>Geese</h2> ...
    <h3>Neck length</h3> ...
    <h3>Instincts</h3> ...

Browser-friendly ToC

The previous examples use a script which is custom-made for Prince. A simplified version of the script produces clicakble links that work both in browsers and in PDF documents. The only downside to using this solution is that CSS pseudo-elements (which were used for counting sections above) are not supported:

htmlh1, h2 { break-before: page }
#toc li { list-style-type: none }
#toc li.h3 { margin-left: 3em; font-style: italic }
#toc a:after { content: leader('. ') target-counter(attr(href), page) }
...
<script type="text/javascript" src="https://princexml.com/howcome/2021/guides/charms.js">
<body onload="simpleToc('h2, h3')">

<h2>Table of Contents</h2>
<ol id=toc></ol>

<h1>Waterfowl</h1>
  <h2>Ducks</h2> ...
    <h3>Feet and feathers</h3> ...
    <h3>Habitat</h3> ...
  <h2>Geese</h2> ...
    <h3>Neck length</h3> ...
    <h3>Instincts</h3> ...

Multipass

Creating indexes in Prince 14 relies on the multipass feature, which formats the document several times. Between each run, a script can modify the document to improve layout. These scripts do amazing things in Prince, but will not work in browsers.

2021-01-06 HÃ¥kon Wium Lie