The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Yes—iText pdfHTML lists both counter-reset and counter-increment as supported CSS properties. In practice, define a named counter, change it on the elements you want to number, and print its value with the CSS counter() function in generated content. Then convert the HTML with iText’s HtmlConverter. The number is not visible until you render it with content (usually on ::before or ::after).
This guide shows a complete Java pattern, explains scope and nested-counter decisions, and separates ordinary sequence numbering from PDF table-of-contents page references. The support matrix is a feature reference, not a promise that every browser edge case renders identically in every pdfHTML release, so test complex nesting against the exact version in your project.
What pdfHTML supports
pdfHTML is iText’s HTML/CSS-to-PDF add-on. A normal Java conversion uses HtmlConverter from the html2pdf dependency. The iText feature matrix lists these properties as supported:
counter-reset, which initializes or reinitializes a named counter.counter-increment, which changes a counter when matching elements are processed.
The same matrix marks counter-set as unsupported. Therefore, support for reset and increment should not be read as support for every modern CSS counter feature. The versioned API documentation also exposes a CssCounterManager and constants for the two property names; those API pages are tied to particular pdfHTML versions, so verify the documentation and matrix for the version you install.
#1 Best Overall
How a CSS counter works
1. Reset or initialize a name
counter-reset: section; creates (or reinitializes) a counter called section. If you do not supply an integer, its initial value is zero. You can set an explicit starting value, and you can initialize more than one counter in the same declaration.
body {
counter-reset: section 0;
}
2. Increment it where numbering advances
counter-increment: section; advances the counter by one on each matching element. An integer changes the step: counter-increment: section 2; adds two, while a negative value decrements it.
h2 {
counter-increment: section;
}
3. Render the value
A counter has no visual output by itself. Use counter(section) in generated content. Use counters(name, separator) when you need a nested representation such as “2.3”.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
h2::before {
content: "Section " counter(section) ": ";
}
The three operations are independent: a reset establishes state, an increment changes state, and counter() or counters() displays state.
Minimal heading-numbering example
This example follows the standard CSS heading-numbering pattern. It is an illustrative CSS pattern; the feature matrix documents property support, but it does not establish that every nesting edge case has been exercised in your release.
Rank #2
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
counter-reset: section;
}
h2::before {
counter-increment: section;
content: "Section " counter(section) ": ";
}
</style>
</head>
<body>
<h2>Installation</h2>
<p>Choose the html2pdf dependency for your project’s iText release.</p>
<h2>Conversion</h2>
<p>Pass the HTML to HtmlConverter.</p>
</body>
</html>
The first h2 displays “Section 1: Installation” and the second displays “Section 2: Conversion” when the installed pdfHTML version processes this pattern as documented.
Nested sections: choose the counter model deliberately
One sequence for all headings
If every heading, regardless of level, belongs to one sequence, increment one counter on all of them:
body { counter-reset: heading; }
h2, h3 {
counter-increment: heading;
}
h2::before, h3::before {
content: counter(heading) " ";
}
This produces a flat sequence. It does not express a hierarchy.
Separate section and subsection counters
For a conventional “2.1” structure, define separate names and reset the child counter when a parent starts:
body {
counter-reset: section;
}
h2 {
counter-increment: section;
counter-reset: subsection;
}
h2::before {
content: counter(section) ". ";
}
h3 {
counter-increment: subsection;
}
h3::before {
content: counter(section) "." counter(subsection) " ";
}
That model makes each h2 restart subsection. If you need deeper levels, add another named counter and reset it at the appropriate parent. Keep names distinct; reusing a name at multiple scopes makes the resulting value harder to reason about.
Nested-counter strings
The CSS counters() function is intended for nested counters. A pattern such as content: counters(section, ".") ". "; can represent a hierarchy with one counter name when the document structure and scope behave as expected. Because the available iText evidence is a support listing rather than a nested-scope test report, validate this form with representative HTML before using it for a contractual document format.
Free tools Windows power users keep installed
One-click scans. No signup required.
Converting the HTML with Java
Add the html2pdf dependency that matches the iText version selected by your project, then compile this class with that dependency and its transitive dependencies on the class path:
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CounterPdf {
public static void main(String[] args) throws IOException {
try (FileInputStream html = new FileInputStream("counter.html");
FileOutputStream pdf = new FileOutputStream("counter.pdf")) {
HtmlConverter.convertToPdf(html, pdf);
}
}
}
Save the CSS/HTML example as counter.html, run the class, and inspect counter.pdf. The Java code does not manually calculate numbers: pdfHTML evaluates the CSS declarations during conversion. Keep the dependency version, Java runtime, and any font configuration consistent between development and production so that layout changes are diagnosable.
Where counters fit—and where they do not
Use CSS counters for custom document numbering
Counters are useful for headings, clauses, figures, callouts, and other elements that are not naturally an HTML list. They let the source remain semantic while the visual prefix is generated at conversion time.
Use ordered lists for list content
If the content is genuinely a list, <ol> and list-style properties communicate list semantics to readers and assistive technology. The iText feature matrix lists list-style properties as supported. CSS counters are not automatically a better replacement; choose them when the numbering belongs to a custom element or heading rather than a list.
Rank #4
Use target-counter for destination page numbers
A sequential counter is not a PDF page reference. For a table of contents that must show the page containing a destination, iText documents target-counter and target-counters support beginning with pdfHTML 3.0.3. Treat that as a separate cross-reference feature. Do not substitute an incrementing heading counter when the reader needs the final PDF page number.
Multiple counters and explicit values
You may initialize several counters in one declaration:
body {
counter-reset: chapter 0 figure 0;
}
.chapter {
counter-increment: chapter;
}
figure {
counter-increment: figure;
}
.chapter::before {
content: "Chapter " counter(chapter) ": ";
}
figure::before {
content: "Figure " counter(figure) ": ";
}
An explicit increment is useful for grouped or weighted numbering:
.major-break {
counter-increment: section 10;
}
.rollback {
counter-increment: section -1;
}
Use unusual step values only when the numbering rule is clear to a reader. A negative increment can produce surprising output if the element appears more than once because of generated or repeated markup.
Scope, generated content, and compatibility cautions
- A reset applies from the element where it is declared according to CSS counter scoping rules. Resetting on a broad ancestor can affect every descendant that uses that name.
- Increment only the elements that should advance. Putting the increment on a container that repeats or wraps content can create extra numbers.
- The counter value is invisible until referenced with
counter()orcounters(), normally insidecontent. - The documented matrix lists properties, not every standards edge case. Browser output and pdfHTML output should not be assumed identical without testing.
counter-setis listed as unsupported; rewrite a design that depends on it using supported reset/increment logic or calculate the value in the source HTML.
Troubleshooting checklist
| Symptom | Likely cause | Fix |
|---|---|---|
| No number appears | The counter is never referenced, or content is missing. |
Add a ::before/::after rule with content: counter(name). |
| Every heading shows the same value | The increment is attached to an ancestor or the named counter is reset repeatedly. | Move counter-increment to the heading selector and reset once at the intended scope. |
| Subsections do not restart | The child counter is not reset when a parent heading begins. | Put counter-reset: subsection on the parent heading (or its deliberate wrapper). |
| Numbers are off by one | The increment occurs on a different element than expected, or an extra matching element exists. | Inspect the generated HTML tree and count matching elements; apply the increment to exactly one element per intended number. |
counter-set has no effect |
The feature matrix marks it unsupported. | Use counter-reset at a defined scope, an explicit source value, or a supported increment pattern. |
| Nested output differs from a browser | Complex scope behavior has not been verified for the installed pdfHTML version. | Reduce the case to a small fixture, check the version-specific matrix/API docs, and test the exact release used in production. |
| Table-of-contents numbers are wrong | A sequence counter was used where a destination page reference was required. | Use the documented target-counter/target-counters capability for page destinations. |
Performance and reliability considerations
Counters themselves are lightweight: they are CSS state evaluated while the document is converted. The larger risks are layout complexity, very large HTML trees, font availability, and relying on behavior outside the documented feature set. Keep a small regression fixture containing the first, middle, last, and nested headings. Compare generated PDFs after every pdfHTML upgrade, especially when changing counter scope or generated-content strings.
Best Value
Do not treat the live support matrix as a version-pinned compatibility contract. The published API references identified for CssCounterManager and CssConstants are for pdfHTML 6.3.3 and 6.3.2 respectively; your project may use another release. Confirm the exact dependency version and test a representative document before promising identical output across environments.
Or skip the browser setup
If your immediate goal is a clean image or PDF of a web page rather than CSS-counter conversion inside iText, ScreenshotNeo provides a single HTTP call. It accepts cookie/consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.
For API parameters and response details, see the ScreenshotNeo documentation. The following call captures a page as WebP:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorscurl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan. Create a free ScreenshotNeo account when you want to try the capture API.
Decision guide
| Requirement | Best-fit approach | Why |
|---|---|---|
| Number custom headings or clauses in source order | CSS counters | Reset and increment named values, then render them with generated content. |
| Represent a semantic list | <ol> with list styling |
Preserves list structure while allowing supported visual styling. |
| Show the PDF page containing a destination | target-counter/target-counters |
Uses cross-reference page information rather than a sequential heading count. |
| Capture a live web page after removing overlays | ScreenshotNeo | Handles consent UI and failed-page billing decisions before returning an image or PDF. |
Frequently Asked Questions
Can I use a counter without a pseudo-element?
Yes. The value must still be rendered through generated content or another supported display mechanism; declaring reset and increment alone does not create visible text.
Should I rely on counter numbering for a legally fixed document format?
Only after testing the exact pdfHTML release, nested structure, fonts, and representative page breaks. The support matrix confirms the properties, but it is not a guarantee for every standards edge case.
Is a heading counter the same as a table-of-contents page number?
No. A heading counter reports sequence position. A table of contents that needs destination pages requires the separate target-counter or target-counters feature.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

