Jekyll heading links


Recently, I added fragment links to my Jekyll blog (see commits).

What this means is when you click on a heading element, the URL will update with the fragment id.

This is useful for bookmarking or sharing a page section. It can also be used when creating a table of contents.

Prerequisites

First, remove all existing heading links from your blog posts. You can find them by grepping the pattern:

git grep '# \[' -- _posts/

Or add the -l option to get all the relative filepaths matching the pattern:

git grep -l '# \[' -- _posts/

Now add your fragment links. Append the script to the end of _layouts/post.html:

<!-- _layouts/post.html -->
<script>
  document
    .querySelector('.post-content') // your selector for the post body
    .querySelectorAll('h1,h2,h3,h4,h5,h6')
    .forEach(function(heading) {
      if (heading.id) {
        heading.innerHTML =
          '<a href="#' + heading.id + '">' + heading.innerText + '<\/a>';
      }
    });
</script>

The script does the following:

  1. looks for all post heading elements
  2. if the element has an id attribute, then the text will be surrounded with an anchor element linking to the fragment id

Example

If you have the following:

<h2 id="title">Title</h2>

Then it would be converted like so:

<h2 id="title">
  <a href="#title">Title</a>
</h2>

Styling

To remove the anchor styles, you can inherit the heading styles:

// main.scss
.post-content {
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    > a {
      color: inherit;
    }
  }
}

If you want to display an icon when the element is active, focused, or hovered, then update your script with:

heading.innerHTML += '<span class="anchor-icon">§</span>';

Then add the CSS to toggle the icon display:

// main.scss
.post-content {
  .anchor-icon {
    display: none;
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    > a {
      &:active,
      &:focus,
      &:hover {
        + .anchor-icon {
          display: inline-block;
        }
      }
    }
  }
}

And there you have it, heading links for your website!



Please support this site and join our Discord!