PrintCSS: Table of Contents
Tags: html, css, printcss, toc
Published: 2021-02-27 23:16:35

A widespread use case for your PrintCSS document is creating a table of contents. But how would you know the page numbers of your chapters before you render the document? The content takes as many pages as it needs, and if your content is dynamic, it is impossible to say how many pages a chapter would result in.

Before we start with our table of contents, we will need some content to create the table. So let’s take the result from my previous article [PrintCSS: Running Headers and Footers](https://medium.com/@azettl/printcss-running-headers-and-footers-3bef60a60d62), and extend the content.

Until now, the content has only one chapter. So we will add “PrintCSS: Table of Contents” with the text above as the second chapter.

    <h1>PrintCSS: Table of Contents</h1>

    <p>A very common use case for your PrintCSS document is creating a table of contents. But how would you know the page numbers of your chapters before you render the document? The content takes as many pages as it needs and if your content is dynamic it is impossible to say how many pages a chapter would result in.</p>

    <p>Before we start with our table of contents we will need some content to create the table for. So let's take the result from my previous article PrintCSS: Running Headers and Footers and extend the content.</p>

This HTML needs to be added inside the div with the class ‘content’.

To separate the chapters, we use the CSS property ‘[page-break-before](https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before)’ (the new version ‘break-before’ does not work with Prince yet) with the ‘always’ value. This will start each chapter on a new page.

    .content h1{
      page-break-before: always;
    }

You can see now that the first page of our PDF is blank, and each chapter starts on a new page. If you want to try it out yourself you can render the code on [printcss.live](https://printcss.live/).

![Rendering Result with Prince, showing the first page empty.](https://cdn-images-1.medium.com/max/2324/1*LY9Yy3GJUmgEasxYvNu46w.png)*Rendering Result with Prince, showing the first page empty.*

![The new second chapter, rendered with Prince](https://cdn-images-1.medium.com/max/2328/1*ZtG-mUJZjx87XyQBZHDj9Q.png)*The new second chapter, rendered with Prince*

The first blank page we will use for our table of contents. In the HTML, we add a new div element with the class ‘toc’ and add the links to our chapters.

    <div class="toc">
      <h1>Table of contents</h1>
      <a href="#running">PrintCSS: Running Headers and Footers</a>
      <a href="#toc">PrintCSS: Table of Contents</a>
    </div>

As you see, we will use anchors to link the table of contents elements to the chapters. This means that each chapter heading needs an ‘id’ attribute.

    <h1 id="running">PrintCSS: Running Headers and Footers</h1>

    ...

    <h1 id="toc">PrintCSS: Table of Contents</h1>

![Links in the PDF with HTML anchors, rendered in Prince.](https://cdn-images-1.medium.com/max/2000/1*8jV1M-hKcKKDePwQRkyyMg.png)*Links in the PDF with HTML anchors, rendered in Prince.*

If you render now and click on one of the table of contents elements, it will already direct you to the correct chapter. But we are missing the page numbers. For that, we can use a CSS function called ‘[target-counter](https://www.w3.org/TR/css-gcpm-3/#target-counter)’.

The first parameter for the ‘[target-counter](https://www.w3.org/TR/css-gcpm-3/#target-counter)’ is the target URL in our case ‘attr(href)’. The second parameter is the counter; as we want the page number, it is ‘page’.

    .toc a{
      display:block;
    }

    .toc a::after {
      content: target-counter(attr(href), page);
    }

![Result of target-counter, rendered with Prince.](https://cdn-images-1.medium.com/max/2000/1*aLEWYIiGvS67rbW2e4BKNQ.png)*Result of target-counter, rendered with Prince.*

To make it look better, let’s add dot leaders with the ‘[leader](https://www.w3.org/TR/css-gcpm-3/#funcdef-leader)’ function.

![Final result with the leader function, rendered with Prince.](https://cdn-images-1.medium.com/max/2340/1*RpdRFKs1ZuIBh3j5kYLQRA.png)*Final result with the leader function, rendered with Prince.*