Skip to main content

PDF Bookmark Guidelines

1. Introduction​

This guide explains how to create and control PDF bookmarks in templates rendered by WeasyPrint and PrinceXML.

PDF bookmarks appear in the navigation panel of a PDF viewer. They allow users to quickly move to important sections of a document.

The goal of this guide is to help template developers:

  • Create bookmarks for document sections.
  • Control the bookmark level.
  • Remove bookmarks from specific headings.
  • Set a custom bookmark label.
  • Keep bookmark behavior consistent across WeasyPrint and PrinceXML.

2. Basic Concept​

Bookmarks are created from HTML elements by using CSS.

A bookmark has two main parts:

  1. Bookmark level --- defines where the bookmark appears in the bookmark tree.
  2. Bookmark label --- defines the text displayed in the bookmark panel.

For example:

<h1>Introduction</h1>
<h2>Background</h2>
<h2>Objectives</h2>
<h1>Implementation</h1>

can produce:

Introduction
Background
Objectives
Implementation

The bookmark hierarchy does not have to exactly match the visual appearance of the document. CSS can control it separately.


3. Create and control bookmarks​

WeasyPrint and PrinceXML support the same bookmark concepts. The only difference for bookmark levels and labels is the CSS property name:

PurposeWeasyPrintPrinceXML
Set bookmark levelbookmark-level-prince-bookmark-level
Remove bookmarkbookmark-level: none-prince-bookmark-level: none
Set bookmark labelbookmark-label-prince-bookmark-label

The examples below use the WeasyPrint property names. For PrinceXML, replace bookmark-level with -prince-bookmark-level and bookmark-label with -prince-bookmark-label.

3.1 Create bookmarks from headings​

A common approach is to use HTML headings:

<h1>Introduction</h1>
<h2>Background</h2>
<h2>Objectives</h2>
<h1>Implementation</h1>

You can explicitly define the bookmark levels:

h1 {
bookmark-level: 1;
}

h2 {
bookmark-level: 2;
}

h3 {
bookmark-level: 3;
}

The resulting PDF bookmark tree is:

Introduction
Background
Objectives
Implementation

Use semantic HTML headings:

  • h1 for major sections.
  • h2 for sections inside an h1.
  • h3 for sections inside an h2.

This makes the document structure easier to understand and maintain.


3.2 Remove a bookmark​

Use:

bookmark-level: none;

For example, to prevent all h2 elements from becoming bookmarks:

h1 {
bookmark-level: 1;
}

h2 {
bookmark-level: none;
}

h3 {
bookmark-level: 3;
}

The h2 elements will still be visible in the document. They will simply not appear in the PDF bookmark panel.

Remove a bookmark from one element​

Use a class when only some headings should be excluded:

<h2 class="no-bookmark">Internal Details</h2>
<h2>Public Details</h2>
.no-bookmark {
bookmark-level: none;
}

Only Internal Details is excluded.


3.3 Create a bookmark from a non-heading element​

A bookmark does not have to come from an h1--h6.

For example:

<div class="chapter-title">Chapter 1 — Introduction</div>
.chapter-title {
bookmark-level: 1;
}

This creates a level 1 bookmark for the <div>.

This can be useful when your template uses custom components instead of normal HTML headings.


3.4 Set a custom bookmark label​

By default, the bookmark label normally comes from the element's content.

You can set a custom label with:

h1 {
bookmark-label: 'Introduction';
}

You can also use the element's content:

h1 {
bookmark-label: content();
}

For example:

<h1>Annual Report</h1>
h1 {
bookmark-level: 1;
bookmark-label: content();
}

The bookmark will be:

Annual Report

3.5 Use an HTML attribute for the bookmark label​

This is useful when the visible heading and the PDF bookmark should have different text.

<h1 class="chapter-title" data-bookmark="Executive Summary">
Executive Summary and Business Overview
</h1>
.chapter-title {
bookmark-level: 1;
bookmark-label: attr(data-bookmark);
}

The document displays:

Executive Summary and Business Overview

while the PDF bookmark displays:

Executive Summary

For reusable templates, data-bookmark is a good way to give template developers explicit control over bookmark text.


3.6 Control the bookmark state​

WeasyPrint supports:

bookmark-state

For example:

h1 {
bookmark-level: 1;
bookmark-state: open;
}

h2 {
bookmark-level: 2;
bookmark-state: closed;
}

This controls whether bookmark children are initially expanded or collapsed in the PDF viewer.

Use this carefully. For large documents, keeping lower-level bookmarks collapsed can make the navigation panel easier to use.


If the same template can be rendered by both engines, use a common HTML convention.

For example:

<h1 class="document-section" data-bookmark="Introduction">Introduction</h1>

<h2 class="document-section" data-bookmark="Background">
Background and Context
</h2>

Then provide engine-specific CSS.

.document-section.level-1 {
bookmark-level: 1;
bookmark-label: attr(data-bookmark);
-prince-bookmark-level: 1;
-prince-bookmark-label: attr(data-bookmark);
}

.document-section.level-2 {
bookmark-level: 2;
bookmark-label: attr(data-bookmark);
-prince-bookmark-level: 2;
-prince-bookmark-label: attr(data-bookmark);
}

HTML:

<h1 class="document-section level-1" data-bookmark="Introduction">
Introduction
</h1>

<h2 class="document-section level-2" data-bookmark="Background">
Background and Context
</h2>

This approach keeps the HTML independent from the rendering engine and both engines still can use one CSS style file.

info

PrinceXML also supports bookmark-level, bookmark-label, bookmark-state
as an alias of -prince-bookmark-level, -prince-bookmark-label and -prince-bookmark-state.

You can use same syntax and they can be rendered by both engines WeasyPrint and PrinceXML.


For a shared template system, use the following convention:

HTML Bookmark Level Recommended Use

h1: Main document section

h2: Section

h3: Subsection

h4: Detailed subsection

h5 / h6: Usually none. Use only when needed

Example:

<h1>Introduction</h1>

<h2>Background</h2>

<h3>History</h3>

<h3>Current Situation</h3>

<h2>Objectives</h2>

<h1>Implementation</h1>

<h2>Architecture</h2>

<h3>Frontend</h3>

<h3>Backend</h3>

Recommended bookmark tree:

Introduction
Background
History
Current Situation
Objectives
Implementation
Architecture
Frontend
Backend

Avoid creating too many bookmark levels. A deep bookmark tree can make the PDF difficult to navigate.

Do not use very long bookmark labels.

Prefer:

Executive Summary
Financial Results
Implementation
Conclusion

Instead of:

Chapter 3 - Financial Results and Detailed Analysis of the Company's Financial Performance During the Reporting Period

The bookmark panel has limited width, so short and meaningful labels are easier to use.

If the visible heading is too long, use data-bookmark to provide a shorter label:

<h1 data-bookmark="Financial Results">
Chapter 3 — Financial Results and Detailed Analysis
</h1>

6. Bookmarks and Table of Contents​

PDF bookmarks and a printed Table of Contents are different features.

PDF bookmarks​

Appear in the PDF viewer's navigation panel:

Introduction
Background
Objectives
Implementation
Architecture

Table of Contents​

Appears as a page inside the document:

Table of Contents

Introduction ...................... 3
Background .................... 4
Objectives .................... 5
Implementation .................... 7
Architecture .................. 8

A document can have:

  • Bookmarks without a printed TOC.
  • A printed TOC without bookmarks.
  • Both bookmarks and a printed TOC.

For a professional document, using both is recommended when the document is large.

Please check Table of Contents section to learn how to create it.