How to add a table of contents in Ghost without editing the site template
How to add a table of contents in Ghost without editing the site template
According to the tutorial here, if you want to add TOC you actually have to edit the site template (i.e., the handlebar file default.hbs
). This is both a hassle and require higher paid tier to do it.
Looking at the tutorial the same can be achieved but direct injecting a small amount of Javascript in your post (or in site settings if you want to do it globally).
Open the side pane and go to "Code injection"
In "Post header" section paste the following (styling tocbot):
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.css">
<style>
.gh-content {
position: relative;
}
.gh-toc > .toc-list {
position: relative;
}
.toc-list {
overflow: hidden;
list-style: none;
}
@media (min-width: 1300px) {
.gh-sidebar {
position: absolute;
top: 0;
bottom: 0;
margin-top: 4vmin;
margin-left: 20px;
grid-column: wide-end / main-end; /* Place the TOC to the right of the content */
width: inline-block;
white-space: nowrap;
}
.gh-toc-container {
position: sticky; /* On larger screens, TOC will stay in the same spot on the page */
top: 4vmin;
}
}
.gh-toc .is-active-link::before {
background-color: var(--ghost-accent-color); /* Defines TOC accent color based on Accent color set in Ghost Admin */
}
</style>
In "Post footer" section paste the following (load and init tocbot, and create the node to mount it):
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.12.3/tocbot.min.js"></script>
<script>
const parent = document.querySelector(".gh-content.gh-canvas");
// Create the <aside> element
const asideElement = document.createElement("aside");
asideElement.setAttribute("class", "gh-sidebar");
//asideElement.style.zIndex = 0; // sent to back so it doesn't show on top of images
// Create the container div for title and TOC
const containerElement = document.createElement("div");
containerElement.setAttribute("class", "gh-toc-container");
// Create the title element
const titleElement = document.createElement("div");
titleElement.textContent = "Table of Contents";
titleElement.style.fontWeight = "bold";
containerElement.appendChild(titleElement);
// Create the <div> element for TOC
const divElement = document.createElement("div");
divElement.setAttribute("class", "gh-toc");
containerElement.appendChild(divElement);
// Append the <div> element to the <aside> element
asideElement.appendChild(containerElement);
parent.insertBefore(asideElement, parent.firstChild);
tocbot.init({
// Where to render the table of contents.
tocSelector: '.gh-toc',
// Where to grab the headings to build the table of contents.
contentSelector: '.gh-content',
// Which headings to grab inside of the contentSelector element.
headingSelector: 'h1, h2, h3, h4',
// Ensure correct positioning
hasInnerContainers: true,
});
// Get the table of contents element
const toc = document.querySelector(".gh-toc");
const sidebar = document.querySelector(".gh-sidebar");
// Check the number of items in the table of contents
const tocItems = toc.querySelectorAll('li').length;
// Only show the table of contents if it has more than 5 items
if (tocItems > 2) {
sidebar.style.display = 'block';
} else {
sidebar.style.display = 'none';
}
</script>
End result, I think tocbot
is quite nice!