Javascript embedded code to display table of content in a knowledge base article

Hi,

As Hubspot doesn’t have for the moment an easy way to generate a table of content from the headers in a knowledge base article, I created some javascript code you can use and insert in an article as Embed element.

Process is:

- Insert embed element in the content of your article:

- Paste the following code into the pop-up field “URL or embed code”

Of course, you can customize custom styles for example to fit your brand choices.

Hope it can help someone, I took me a lot of time to obtain this result!

Javascript code:

<style>
.sidenav__item {
	list-style-type: disc; 
	text-decoration: none;
}
a { 
	text-decoration: none;
}
a.kb-custom-link {
	text-decoration: none;
}
a.kb-custom-link:link {
	text-decoration: none;
}
a.kb-custom-link:hover {
	color: #44A5D8;
	text-decoration: none;
}
</style>

<div class="hs-table-align-left" style="overflow-x: auto; max-width: 60%; width: 60%; margin-left: auto; margin-right: auto;" data-hs-responsive-table="true">
<table style="width: 100%; border-collapse: collapse; table-layout: fixed; border: 1px solid #99acc2; height: 35.8px; border-style: hidden;">
<tbody>
<tr style="height: 35px;">
<td style="width: 100%; padding: 4px; height: 35px;">
<p>
	<strong>Table of Content</strong>
	<hr>
<blockquote id="tableOfContent"></blockquote>
<hr>
</td>
</tr>
</tbody>
</table>
</div>

<script>
//FOR TABLE OF CONTENT
window.addEventListener('DOMContentLoaded', function (event) { // Let the DOM content load before running the script.
//Get all headings only from the actual contents.
var contentContainer = document.getElementsByClassName('kb-content')[0]; // Add this div to the html
var headings = contentContainer.querySelectorAll('h3,h4'); // You can do as many or as few headings as you need.

var tocContainer = document.getElementById('tableOfContent'); // Add this div to the HTML
// create ul element and set the attributes.
var ul = document.createElement('ul');

ul.setAttribute('id', 'tocList');
ul.setAttribute('class', 'sidenav')

var currentLIH3;

// Loop through the headings NodeList
for (i = 0; i <= headings.length - 1; i++) {

 var id = headings[i].innerHTML.toLowerCase().replace(/ /g, "-"); // Set the ID to the header text, all lower case with hyphens instead of spaces.
 var level = headings[i].localName.replace("h", ""); // Getting the header a level for hierarchy
 var title = headings[i].innerHTML; // Set the title to the text of the header

 headings[i].setAttribute("id", id) // Set header ID to its text in lower case text with hyphens instead of spaces.

 var li = document.createElement('li'); // create li element.
 li.setAttribute('class', 'sidenav__item') // Assign a class to the li
	li.setAttribute('style', 'margin-top: 0px; margin-bottom: 0px;')

 var a = document.createElement('a'); // Create a link
 a.setAttribute("href", "#" + id) // Set the href to the heading ID
	a.setAttribute("rel", "noopener"); //To have anchor from TOC links working correctly
	a.setAttribute('class', 'kb-custom-link')

	a.innerHTML = title; // Set the link text to the heading text

 // Create the hierarchy
 if(level == 3) {
 li.appendChild(a); // Append the link to the list item
 ul.appendChild(li); // append li to ul.
		currentLIH3 = li;
 } else if (level == 4) {
 child = document.createElement('ul'); // Create a sub-list
 child.setAttribute('class', 'sidenav__sublist')
		child.setAttribute('style', 'margin-top: 0px; margin-bottom: 0px;')
 li.appendChild(a); 
 child.appendChild(li);
 currentLIH3.appendChild(child);
	}	
}

tableOfContent.appendChild(ul); // add list to the container

// Add a class to the first list item to allow for toggling active state.
var links = tocContainer.getElementsByClassName("sidenav__item");

links[0].classList.add('current');

// Loop through the links and add the active class to the current/clicked link
for (var i = 0; i < links.length; i++) {
 links[i].addEventListener("click", function() {
 var current = document.getElementsByClassName("current");
 current[0].className = current[0].className.replace(" current", "");
 this.className += " current";
 });
}
});

</script>

Hey, @ClaireBIGENIUS. Thank you for sharing! — Jaycee