DEV Community

Cover image for Finally a clean and easy way to add Table of Contents to dev.to articles ๐Ÿคฉ
Lucy Linder
Lucy Linder

Posted on • Updated on • Originally published at blog.derlin.ch

Finally a clean and easy way to add Table of Contents to dev.to articles ๐Ÿคฉ

Contrary to other platforms, dev.to doesn't have built-in support for Table of Contents (TOCs). Many articles describe tricks to generate TOCs, but those are often laborious and lack a clean UI.

I am thus proud to announce โœจโœจBitDownToc now supports dev.toโœจโœจ!

BitDownToc


How to add TOCs to dev.to articles

Start by copying your article content. Then:

  1. go to https://derlin.github.io/bitdowntoc/,
  2. select the dev.to preset,
  3. copy-paste your article into the left box,
  4. click on generate,
  5. click on copy.

You now have your article content with TOC on your clipboard!

You can even redo the manipulation after an update to the article since BitDownToc is idempotent by default!

BitDownToc interface with dev.to preset

For the dark lovers out there, you can toggle the dark theme using the first icon on the top right ๐Ÿ˜‰


โ†“ Table of Content (generated by BitDownToc) โ†“


Why are TOCs important?

A table of contents (TOC) is important because it helps navigate the content and find specific information quickly. It allows readers to grasp in seconds what the article is about and to potentially jump to the section they are interested in in a click. It improves the overall organization, readability, and usability of the article.

How do TOCs work?

A table of contents is simply a list of fragment links (#xxx), with each link pointing to a section in the document - called an anchor.

Anchors are used to link to a specific location within the same webpage. Previous to HTML5, they were created using the <a> element and a name attribute, which is now deprecated in favor of the id attribute:

<!-- for old browser ... --->
<a name="section1">Section 1</a>
<!-- ... or for modern browser supporting HTML5 -->
<h2 id="section1">Section 1</h2>
Enter fullscreen mode Exit fullscreen mode

To refer to an anchor, one can use a link with a # symbol - called a fragment link. From the example above:

<a href="#section1">Jump to Section 1</a>
Enter fullscreen mode Exit fullscreen mode

TOCs on dev.to

Dev.to automatically generates anchors for headings using the following algorithm:

  1. take the heading text,
  2. lowercase everything,
  3. drop any character that isn't a letter, a digit, or a space,
  4. merge consecutive spaces into a single one
  5. replace spaces with dashes.

To manually add a TOC to a dev.to article, we thus need to generate the TOC with the proper fragment links:

## Table of Contents
- [Introduction](#introduction)
- [This ;;; is Main.   Body](#this-is-main-body)
- [Conclusion  (yup)](#conclusion-yup)


## Introduction
...

## This ;;; is Main.   Body
...

## Conclusion  (yup)
...
Enter fullscreen mode Exit fullscreen mode

This is tiresome to do... Hence BitDownToc!

Advantages of BitDownToc

There have been multiple solutions proposed to generate TOCs on dev.to articles in an "automatic" fashion, for example:

BitDownToc, however, offers more: idempotency and TOC placement.

An idempotent operation produces the same result no matter how many times it is applied. In other words, you can re-run BitDownToc on the same article multiple times: it will either update the TOC (if needed) or leave it as is.

To support this feature, TOC (and anchors) are wrapped within small comments. Those comments are usually in HTML (<!-- ... -->), but since dev.to doesn't support them (๐Ÿ˜ฆ), the dev.to preset uses liquid tags instead ({%- # ... -%}).

The above example will look the same, but with liquid comments around the TOC:

...

{%- # TOC start -%}
- [Introduction](#introduction)
- [This ;;; is Main.   Body](#this-is-main-body)
- [Conclusion  (yup)](#conclusion-yup)
{%- # TOC end -%}

...
Enter fullscreen mode Exit fullscreen mode

Another great feature of BitDownToc is the ability to control where the TOC will appear in the article using the marker [TOC]. Any heading above this marker won't be part of the TOC.

Many more options are available! Toggle them by clicking on Options:

BitDownToc options

If you always use the same options, click on Save to make them the defaults ๐Ÿ˜‰.

(Bonus) TOCs on other platforms

BitDownToc is meant to be universal. To make it easy to use, it comes with presets for most developer platforms such as GitHub, Gitlab, and BitBucket Server.

Most markdown renderers generate anchors automatically for each section. The challenge is to find out how this generation works.
On GitHub, for example, the title is lowercased, all special characters (other than letters, digits, and spaces) in the heading are dropped, and spaces are replaced with dashes.
Gitlab and dev.to merge consecutive spaces into a single one before performing the same logic. This option is called concat-spaces in BitDownToc.
HashNode works like Gitlab, but prefixes anchors with heading-. This option is called anchors-prefix in BitDownToc.

For renderers that do not generate anchors (or if the anchor's generation algorithm is too convoluted), BitDownToc can generate its own anchors directly in the markdown. This is what it does for BitBucket Server.

๐Ÿ—’๏ธ Note that if you inspect the HTML of any README on GitHub or Gitlab, you won't see the "real" anchors. A markdown like:

## Introduction
Enter fullscreen mode Exit fullscreen mode

Will be translated to the following HTML snippet:

<h2 dir="auto">
  <a id="user-content-introduction"
     class="anchor" href="#introduction"
     aria-hidden="true"></a>
  Introduction
</h2>
Enter fullscreen mode Exit fullscreen mode

This is because both platforms handle hash changes via Javascript, with a code that (probably) looks like this:

addEventListener('hashchange', () => {
  const hash = location.hash.toLowerCase();
  const elem = document.getElementById(`user-content-${hash}`);
  elem.scrollIntoView();
});
Enter fullscreen mode Exit fullscreen mode

Find out more about BitDownToc on GitHub โฎ• https://github.com/derlin/bitdowntoc

Top comments (17)

Collapse
 
michaeltharrington profile image
Michael Tharrington

Rock on! Awesome work, Lucy! ๐Ÿ™Œ

This actually came up in discussion last week in @szabgab's post here:

The post is about more than just ToCs, but Gabor illustrates his point with an example saying it'd be cool to have the option to see the raw MD of a post to see how folks are creating interesting things in MD, like a ToC.

Anywho, it's just really cool to see this come to fruition a week after that convo. Really appreciate ya adding DEV support to this tool!

Collapse
 
derlin profile image
Lucy Linder

Thanks for the kind words and the share !
Good timing indeed ๐Ÿ˜„ I am all for the "show source" button, it would be an awesome addition to dev.to. Markdown is so easy and yet so complex at times!

Collapse
 
derlin profile image
Lucy Linder • Edited

UPDATE: I just discovered dev.to DOES create anchors (GitLab style - with space concatenation). I just updated BitDownToc online and the article to match this finding!

Collapse
 
cicirello profile image
Vincent A. Cicirello

Cool approach to generating TOCs for DEV posts.

Your explanation of how to manually add a TOC on DEV isn't entirely correct. You don't actually need to create the anchors yourself. DEV automatically creates anchors for every section just like GitHub does in READMEs.

The anchor is formed by dropping any symbols from the section heading, lowercasing the section heading, and replacing spaces with dashes. For example, the following section heading:

## Section Heading + Hyphenated-Word
Enter fullscreen mode Exit fullscreen mode

Will get an anchor by removing the + and -, lowercasing everything and replacing spaces with -. So you can link to it with:

[Link Text](#section-heading-hyphenatedword)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
derlin profile image
Lucy Linder • Edited

Yeah, I just saw... I feel stupid having missed that... I updated BitDownToc online to match this finding and changed part of the article, thank you !!

Collapse
 
cicirello profile image
Vincent A. Cicirello

No reason to feel stupid. It is more of an example of the importance of your TOC tool. It seems every site's markdown processor is a little different. Your TOC tool looks very useful especially because of that. With your tool, there is no reason to remember the differences in how anchors are formed. Very cool. Maybe there's a way to integrate it directly with DEV's editor.

Collapse
 
farcellier profile image
Fabien Arcellier

It's excellent. I love that it's idempotent and at any point in writing I can generate the table of contents again. Thank you :)

Collapse
 
pixelrena profile image
Serena

Very useful and quick!! Thanks so much, I didn't think such a tool would exist :o

Collapse
 
bcouetil profile image
Benoit COUETIL ๐Ÿ’ซ • Edited

Thank you, very useful ๐Ÿ™

May I suggest 2 things :

  • Adding a comment saying where it is generated, then I would not have to remember :
<!-- TOC generated with https://derlin.github.io/bitdowntoc/ -->
Enter fullscreen mode Exit fullscreen mode
  • TOC start/end should be one empty line away from actual TOC, because IDEs like VSCode want to add one before TOC start and want to indent TOC end with last section, forcing me to edit before saving.
{%- # TOC start -%}

- [Introduction](#introduction)
  - [S3 specific outputs](#s3-specific-outputs)
- [Conclusion](#conclusion)

{%- # TOC end -%}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
derlin profile image
Lucy Linder

Very good suggestions indeed! Can you create issues on github so I don't forget them? Thank you for your valuable input

Collapse
 
bcouetil profile image
Benoit COUETIL ๐Ÿ’ซ

done ๐Ÿ˜Š

Collapse
 
zankyr profile image
zankyr

Awesome!
I have always been very comfortable with the IntelliJ feature to generate a TOC: a simple key combination et voilร , the TOC is created.
But I realized that the format used is not understood by everyone : for example Visual Studio Code and dev.to do not digest very well the <!-- TOC --> tags generated by IJ (the closing tag is always displayed in the generated markdown).
Also, I found that some particular headers are not well managed. For example this anchor
[Delete all local branches not matching the provided name(s)](#delete-all-local-branches-not-matching-the-provided-name--s-) doesn't work in dev.to. The same anchor, generated by bitdowntoc, works just fine: [Delete all local branches not matching the provided name(s)](#delete-all-local-branches-not-matching-the-provided-names)

Collapse
 
derlin profile image
Lucy Linder

So happy you liked it!
dev.to anchor generation is a mess... It took me a while to figure out how to reproduce the algorithm using Kotlin Multiplatform. I am planning on writing an article about it, stay tuned!

Collapse
 
yo1995 profile image
Ting • Edited

Welp, I guess this is kind of a clickbait title. ๐Ÿคทโ€โ™‚๏ธ There have been many Markdown TOC tools available, and I only decide to give this a read because I thought dev.to is gonna support TOC natively, just like GitHub markdown. If I need to copy paste my content back and forth just to generate TOC, then I probably gonna mess up the formatting at some point.

Collapse
 
derlin profile image
Lucy Linder

Did you give bitdowntoc a try before writing this comment?

I would be interested in your advices to make the experience more streamlined. Currently you copy from dev.to, paste to bitdowntoc, click, click, paste again on dev.to. This makes it difficult to "mess up".

The only better approach would be a chrome extension integrating bitdowntoc, but I unfortunately don't have time for that right now.

Collapse
 
yo1995 profile image
Ting

Thanks for your response. I tried the tool and it works as explained. My complaint was only about the title "Finally a clean and easy way to add Table of Contents to dev.to articles" - I was hoping to see Dev.to adding this functionality natively, but apparently they don't bother doing this.
Using online editor might be easy for edit-what-you-see workflow, but when it comes to managing separately hosted images, copy-paste get a a bit tricky. Thus I hope they'll have a native TOC button online, or I have to stick to the local editor with plugin.

Thread Thread
 
derlin profile image
Lucy Linder

+1 for a built-in tool!