Why don't headings display segment numbers (ids)?

When “Main” references are turned on, we see all of the segment numbers except those for headings and sub-headings. Those segment numbers exist and will even work if used. For example,


Will take you right to where you want:

But you have to dig into the html to find them.

I realize that displaying them is kind of ugly, especially because there may already be numbers that are a visible part of the text of the heading.

However if I want beauty, I will turn off the segment numbers completely :grin:

In practice this means it’s not easy to link to a section heading. Instead I have to link to the first segment in the heading. Or I have to go digging in the code.

To be clear, I’m not talking about the numbers that appear in the text of the heading as discussed in this old thread.

Bhante @Sujato, is there a reason it’s like this? Are you open to changing how it works so the segments are displayed?


As I’m getting closer to needing this feature, I played around with the css for the site.

It appears that the only thing keeping the heading ids from displaying is css. So to display them, you just need to add this custom css into a plugin like Stylus:

h2 .reference, h3 .reference, h4 .reference, h5 .reference{

If you have this added, the following link will take you to heading 4.2:

But if you don’t, then it doesn’t work. Why? Because there are ids for segments and there are ids for the segment numbers. I somehow never noticed this before. So for example, this is the html:

<span class="segment" id="dn1:3.45.0">
	<span class="reference">
		<a class="sc refFocused" id="3.45.0" href="#3.45.0" title="SuttaCentral segment number">3.45.0
	<span class="translation" lang="en">
		<span class="text">4.2. Conditioned by Contact 
	<span class="root" lang="pli" translate="no">
		<span class="text">4.2. Phassapaccayāvāra 

What I didn’t know was that if an html element with an id is hidden using css, then that id won’t be linkable. So strange.

If I want to actually link to this spot, instead of using the id for the segment number, I need to use the id for the segment. Because the segment numbers for the headings are always hidden. So this:

Notice thr dn1:


I mean, it’s not that strange in the sense that the CSS can move an element anywhere around the page, so to scroll an element into view, the browser obviously needs to load the CSS and lay out the page to find out where to scroll to… and if an element isn’t on the page at all, it isn’t so strange that it just wouldn’t scroll at all (even if we might prefer it to scroll to where that element would be if it were displayed)


I guess it’s strange to me that css could break a link. But I get why it works like that.

Perhaps what is strange is that the built in segment linking system is linking to segment numbers and not segments. I’m guessing that links to pages are processed so that if the url includes an anchor that that type of ref is rendered visible.


Well, there are empty segments right? Like some Pāḷi repetitions that Bhante’s translation skips over? So if the user is viewing English-only, those segment elements still wouldn’t exist…

They exist. They just contain no content.

Any way, this is all kind of separate from the issue of headings not showing their segment numbers.

I realize that I could just be linking to the first text segment under the heading. But if I’m trying to reference the whole section, that doesn’t seem appropriate.


it seems that you can’t link to a div which is set to 'display:none;'

There are many way of hiding things. Some of which remove the box model, and therefore the link.

It might be necesary to make the references height:1px; width:1px; overflow hidden; and have it toggle to height:auto; width:auto; when the refs are shown.


Yes, the underlying rationale is that as a general rule you shouldn’t stick anything on headings.


1 Like

Actually a really common pattern I see is that when you hover over a heading that a link icon appears so you can copy an exact link to a heading. Because it’s so expected to want to link to a heading of a section.

How would you suggest to solve the problem of wanting to link directly to a section instead of to an individual segment?

Edit to ask:

And if you don’t want to solve the “problem”, can I at least count on linking to the segment id of the headings in Bilara translations continuing to work? E.g. suttacentral.net/dn1/en/sujato#dn1:3.45.0 (I’m really only concerned with the DN)

1 Like

Okay yes, that’s true, I guess I’m thinking print-first.

Yes, we won’t be changing the ID structure.

1 Like

OK, that’s all good to know. Thanks!

Since it’s taken me a bit to work this out, I thought I would share my custom code in case anyone runs into the same issue I did.

My use case is that I will be indexing the DN soon. Instead of just targeting whole suttas, I’d like to be able to target sections. I decided to target the ids of the headings rather than the ids of the segment numbers.

This css makes the headings 'sticky' at the top of the page:
h2, h3, h4 {
  position: -webkit-sticky; /* For Safari */
  position: sticky;
  top: 0;
  background: white; /* Optional: add a background color to avoid text overlap */
  z-index: 1; /* Optional: ensures h2 stays on top of other elements */
  padding: 10px 0; /* Optional: adjust spacing as needed */
  border-bottom: 1px solid #ccc; /* Optional: visual separation */

It can be injected using a browser plugin like Stylus

This is the JS that copies the id of a heading to the clipboard when you click on the text of the heading
// ==UserScript==
// @name         click to copy heading ids
// @namespace    http://tampermonkey.net/
// @version      2024-07-06
// @description  click to copy heading ids
// @author       ChayGpt
// @match        https://suttacentral.net/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=suttacentral.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    console.log("Tampermonkey script loaded");

    // Function to copy text to clipboard
    function copyToClipboard(text) {
        const tempInput = document.createElement('input');
        tempInput.style.position = 'absolute';
        tempInput.style.left = '-9999px';
        tempInput.value = text;

    const addedEventListeners = new Set();

    // Function to add event listeners to all heading tags within article tags
    function addEventListeners() {
        const headings = document.querySelectorAll('article h2, article h3, article h4, article h5');

        headings.forEach(heading => {
            if (!addedEventListeners.has(heading)) {
                heading.addEventListener('click', function(event) {
                    event.preventDefault(); // Prevent the default action
                    console.log("heading tag clicked:", heading);
                    const childSpan = heading.querySelector('span');
                    if (childSpan && childSpan.id) {
                        console.log(`Copied ID: ${childSpan.id} to clipboard`);
                    } else {
                        console.log('This heading tag does not have a child span with an ID');

    // Run the function initially

    // Observe changes to the DOM
    const observer = new MutationObserver(addEventListeners);
    observer.observe(document.body, { childList: true, subtree: true });

It can be injected using a browser plugin like TamperMonkey

Note to @moderators: I generated this code using ChatGPT. I don’t know how that fits with policies. Shared code should always be used at the user’s own risk. I don’t think this code is dangerous in any way, though.

1 Like