Skip to content

Instantly share code, notes, and snippets.

@deanebarker
Last active November 21, 2023 16:39
Show Gist options
  • Save deanebarker/63a67eb52c1fbc3522fc715669e91cb7 to your computer and use it in GitHub Desktop.
Save deanebarker/63a67eb52c1fbc3522fc715669e91cb7 to your computer and use it in GitHub Desktop.
Web Component to embed a dynamic table of contents based on heading tags
/*
<table-of-contents title="Contents" source=".article" selector="h2,h3"></table-of-contents>
* "title" will be placed in a HEADER tag as the first child
* "source" default to the BODY tag
* "selector" defaults to "h2"
OR
<table-of-contents source=".article" selector="h2,h3">
<header><em>This is the table of contents...</em></header>
<!-- items will be added here -->
</table-of-contents>
It will use the innerText of the selected element, wrapped in a DEV, or this can be over-ridden with an attribute of "data-toc-title".
<h2>This will be used as the title</h2>
<h2 data-toc-title="This will be used instead">This will NOT be used as the title</h2>
*/
class TableOfContents extends HTMLElement {
get selector() {
return this.getAttribute('selector') ?? 'h2';
}
set selector(value) {
this.setAttribute('selector', value);
}
get source() {
return this.getAttribute('source') ?? 'body';
}
set source(value) {
this.setAttribute('source', value);
}
get title() {
return this.getAttribute('title');
}
set title(value) {
this.setAttribute('title', value);
}
constructor() {
super();
document.addEventListener('DOMContentLoaded', () => this.init());
}
static get observedAttributes() {
return [ "selector", "title", "source" ];
}
attributeChangedCallback() {
this.init();
}
init() {
let items = document.querySelector(this.source).querySelectorAll(this.selector);
if(items.length == 0) {
this.style.display = "none";
return;
}
if(this.title != null) {
var header = document.createElement("header");
header.innerHTML = this.title;
this.appendChild(header);
}
var counter = 1;
items.forEach((e) => {
e.setAttribute("id", "h" + counter);
counter++;
var link = document.createElement("a");
link.setAttribute("href", "#" + e.getAttribute("id"));
link.setAttribute("class", "tocItem" + e.tagName);
if (e.getAttribute("data-toc-title")) {
link.innerHTML = e.getAttribute("data-toc-title");
} else {
link.innerHTML = e.innerText;
}
var item = document.createElement("div");
item.appendChild(link);
this.appendChild(item);
});
}
}
customElements.define("table-of-contents", TableOfContents);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment