Adding Table of Contents to Dev.to Posts

Sunder Iyer - Mar 19 '21 - - Dev Community

I uploaded another game design article which originally had Table of Contents (ToC from here on) and I wanted to recreate that section in my dev.to post.
Fortunately, every header tag on dev.to is nicely anchored. Good job, Dev team!

So, Markdown data of headers like this...

## Section
## Another Section
### Sub-Section
Enter fullscreen mode Exit fullscreen mode

...produces...

<h2>
  <a name="section" href="#section" class="anchor"></a>
  Section
</h2>
<h2>
  <a name="another-section" href="#another-section" class="anchor"></a>
  Another Section
</h2>
<h3>
  <a name="subsection" href="#subsection" class="anchor"></a>
  Sub-Section
</h3>
Enter fullscreen mode Exit fullscreen mode

And so, to produce ToC in Markdown, you can write something like...

## Table of Contents
1. [Section](#section)
2. [Another Section](#another-section)
    1. [Sub-Section](#subsection)
Enter fullscreen mode Exit fullscreen mode

It's important to note how the reference gets converted. As you can see from the second and third headers, spaces become hyphens and hyphens are removed. Oh and it's all lowercase.


Of course, if you have many big articles, writing each ToC by hand might be tedious and prone to error. I quickly hacked up this script which seems to work "okay" when I run it in my browser's console with the Dev.to Preview tab up.

var anchors = document.getElementsByClassName("anchor");
var outputMarkDown = "## Table of Contents\n";
var orderedNumbers = { };
for (var item in anchors)
{
    var anch = anchors[item];
    var pelm = anch.parentElement;
    var sibl = anch.nextSibling;
    // parent is necessary as this is the header tag used
    // next sibling is necessary as this is the header text
    if (!parent || !sibl) continue;
    // indent n times 4 spaces (considers h2 to be first, hence -2)
    var indent = pelm.nodeName.slice(-1) - 2;
    outputMarkDown += "    ".repeat(indent);
    // add number
    if (!orderedNumbers[indent]) orderedNumbers[indent] = 1;
    outputMarkDown += orderedNumbers[indent]++ + ". ";
    // add links
    outputMarkDown += "[" + sibl.textContent.trim() + "](" + anch.hash + ")\n";
}
console.log(outputMarkDown);
Enter fullscreen mode Exit fullscreen mode

This is what it produced when I ran it on the article linked at the top of this post.
Test Result ToC

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .