Table of Contents in Ghost
Automatically generated table of contents in Ghost, conditionally shown when it is not empty.
Update 3/2023, also check this out, it's simpler
Auto Generate TOC
I largely followed the excellent instructions here
Adding TOC: see commit
Styling TOC: see commit
Note: there is a recent fix in the theme regarding scroll-margin-top
.post-full-content h1,
.post-full-content h2,
.post-full-content h3,
.post-full-content h4,
.post-full-content h5,
.post-full-content h6 {
color: color-mod(var(--darkgrey) l(-5%));
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
scroll-margin-top: 110px;
}
It makes the TOC scrolling a bit weird and is redundant with, we can keep either one of them.
.post-content h2::before,
.post-content h3::before {
display: block;
content: " ";
height: 84px;
margin-top: -84px;
visibility: hidden;
}
Make it Conditional 🎉
Now, there are a few problems. Because the styling is applied on all .post-full-content
there are two issues
- Post without TOC will still have its main text area off-centered to make room for the TOC that doesn't exist
- Pages will not have POC (because we only adjusted
post.hbs
, but it will also make its content off-centered for TOC area on the right
The main thing making this extra column appear is
.post-full-content {
display: grid;
grid-template-columns: 1fr 0.2fr;
padding: 0 0 6vw;
margin: 0;
}
We can give it a more special name .post-full-content-with-toc
.
Then we only add this class to post pages which actually have a non empty TOC. One way to achieve this is to add the following Javascript somewhere, for example in post.hbs
's script block (see commit here).
var hasTOC = $(".toc").children().length
if (hasTOC)
{
$(".post-full-content").addClass("post-full-content-with-toc");
}
Optional Configurations
Optionally, you can also disable TOC when there aren't say more than 5 entries in the TOC list.
var hasTOC = $(".toc").children().length;
if (hasTOC) {
var n = $(".toc li").length;
if (n < 5) {
$(".toc").remove();
} else {
$(".post-full-content").addClass("post-full-content-with-toc");
}
}
One small thing related to membership, when a reader does not have access to a post, there will be a call to action (CTA) but no content, in this case it doesn't make sense to have a TOC either. To adjust for this, wrap the previous <aside>
section with {{#if access}}
to check whether the user has access to the post.
{{#if access}}
<aside class="toc-container">
<div class="toc"></div>
</aside>
{{/if}}
See here for more Ghost editing tips: 👇