JavaScript Engineering

Fixing Missing Auto-Numbered Headings in Confluence via Bookmarklet

My documentation workflow hit a wall when I realized Confluence lacks native support for hierarchical header numbering. Manually updating indices after every structural change is unsustainable, so I built a surgical, client-side injection to handle the numbering on demand.

Need the supporting files, visual references, or downloadable resources that normally sit behind this kind of workflow?

Open on 3DCGHub

1. Identifying the Pain Point

The problem was simple: I was maintaining a long-form technical specification in Confluence and the lack of automatic chapter numbering made the outline impossible to navigate. Every time I inserted a new section, I had to manually update every subsequent header index, which is prone to human error.

I initially searched for native settings or plugins within our instance. While commercial add-ons existed, they were bloated for this specific need and required administrator approval. I decided that a lightweight, client-side approach would be faster to deploy and easier to maintain.

  • Confirmed Confluence lacks built-in CSS or structural numbering.
  • Evaluated third-party marketplace options as overkill.
  • Identified browser-based execution as the most flexible path.

2. Exploring DOM Manipulation

My first instinct was to hook into the page load cycle, but Confluence's dynamic content rendering makes event listeners unreliable. Instead, I opted for an on-demand trigger mechanism, ensuring the script only runs when I explicitly request a renumbering.

I inspected the DOM structure to identify which heading tags (H1 through H6) were present. I needed a recursive function to track the state of each header level, resetting sub-counters whenever a parent level incremented.

  • Targeted standard HTML header elements within the editor container.
  • Used a simple array to track current index counts per level.
  • Verified selectors for consistency across different Confluence versions.

3. Implementing the Bookmarklet

I wrote a compact JavaScript function that traverses the DOM nodes and prepends a formatted string to the text content of each header. I wrapped this logic in an IIFE (Immediately Invoked Function Expression) to avoid polluting the global namespace while active.

To make this accessible, I converted the code into a bookmarklet. This allows me to toggle the numbering instantly from my browser's bookmarks bar without modifying the underlying wiki markup or requesting server-side changes.

  • Encapsulated logic within a URL-encoded script bookmark.
  • Implemented reset logic to prevent redundant numbering on successive clicks.
  • Ensured compatibility with standard browser security policies.

4. Verification and Limitations

I verified the script by running it against a complex document with nested H2 and H3 structures. The output accurately rendered '1.1', '1.2', and '2.1' sequences. It is important to note that this is a client-side visual fix; the underlying data in Confluence remains unchanged.

This tool works best for personal drafting. If your team relies on printed exports or PDF generation, verify that your export engine supports the style changes, as client-side DOM injections may not persist in server-side generated documents.

  • Tested performance on pages with over 50 heading elements.
  • Confirmed index resets correctly on parent header changes.
  • Documented that styles are visual and do not persist in raw exports.

FAQ

Will this script break when I refresh the page?

Since this is a client-side script triggered by a bookmark, the changes are not persistent. You will need to click the bookmark again if you refresh or navigate away.

Can I customize the numbering format?

Yes. The logic uses simple template literals to join the indices. You can modify the joining character (e.g., changing dots to hyphens) directly in the source code before creating your bookmark.