4 Quality Options for a Table of Contents Block in WordPress

Avatar of Chris Coyier
Chris Coyier on

Offering a table of contents block in WordPress for blog posts (or really any other type of long-ish written content) is a good idea for two reasons:

  • It helps users jump around in the post for what they need (and hopefully doesn’t get in the way).
  • It’s provides SEO value.

The RankMath SEO plugin factors it in as part of your page score (suggesting you should have one), because of that second point. See what Google likely gives you if you do it right:

Screenshoot of a typical Google search results item with a breadcrumb above the page title, then a page description. A purple box is drawn around four links below the page description to call out how adding a table of contents block in WordPress can add those links in the search results for additional user convenience,

It makes sense that other WordPress SEO Plugins like Yoast offer a table of contents block as a baked-in additional feature of the plugin. If you’re committed to using Yoast, then I think it’s fine to just use that. But I admit it’s not my favorite to feel locked to a plugin because it offers a microfeature that you then depend on.

So what are the options?

Table of Contents

What to look for in a WordPress Table of Contents Block

Here are some things to look for and think about when choosing a table of contents block:

  • Customizable header — Many options chuck a “Table of Contents” header above the actual Table of Contents, which makes sense. Can you turn it off or customize it? What level header is it? Having the ability to disable the heading might be necessary for layout, and having a choice of heading levels can help ensure proper HTML semantics.
  • Collapsible — In the spirit of making the Table of Contents less annoying, many offer a feature to toggle the Table of Contents block between open and closed states. Do you want that? Are you OK with the fact it likely requires some JavaScript to work? Is it doing toggling accessibly? Can it default to the state that you want?
  • Choose which headings to include — Perhaps you only want all the <h2> elements to form the Table of Contents. Can you do that? Do sub-headers create a “nested’ list? Do you want that? Can you turn off certain levels of headers? Can you tell the block to only include <h2> through <h4>? Are there things other than headers you want to be part of the Table of Contents?
  • Editable links — Many Table of Contents plugins in WordPress typically grab all the headings verbatim. Maybe you want to shorten, lengthen, or otherwise change a specific link in the Table of Contents; as in, not have it be the exact text of the header it links to. Can you do that?
  • Include additional links — Perhaps you want to link to something that isn’t a content heading. Perhaps it’s added to the template with a WordPress custom field, or it’s part of the overall template like the comments section. Can you add (or remove) those as headings in the block?
  • Block Editor support — That’s kind of the point of this blog post. I didn’t include many options that don’t have a block. But surely there are old school versions of this that are [shortcode]-based or that implement it some other way. I’m mostly concerned about blocks, although I could easily see a situation where your goal is to put the Table of Contents elsewhere in a template (sidebar, perhaps?). So, having multiple options and modularity could be useful.
  • Styling options — Personally, I like to bring my own styling (surprise!) and even dequeue any stylesheets (or scripts) that a plugin tries to bring along for the ride. But I can imagine more folks want the Table of Contents to look good and be able to aesthetically control it right from the editor. This means it’d be nice to have block options for colors, fonts, spacing, etc.
  • Semantic markup — Might be worth a peek at the HTML that the Table of Contents block you choose generates to make if it’s sensible. I’ve seen plugins generate HTML lists that don’t actually nest lists, for example, but instead add classes to list items to make them look nested. No, thanks. I’m not sure there is an official HTML format that’s best for SEO, so sematic markup is about the best you can do.
  • Heading IDs — In order for a linked Table of Contents to work, all the headers need to have IDs so there’s something to anchor to. I would think any plugin here that’s worth its salt would add them to headings only in the case that they don’t already have one, but you might wanna veryify that; otherwise, you run the risk of breaking existing links or perhaps even styling and functionality. Also think about what IDs are being generated. For example, I use the Add Anchor Links plugin, which adds a link (🔗) icon beside all headings to offer access to the IDs. The IDs it generates were idential to the Table of Contents-generated IDs, causing a duplicate ID problem. Fixable, but just be aware of things like that.

Option 1: Use a Dedicated Table of Contents Plugin

A dedicated Table of Contents plugin is a plugin that focuses on nothing but a Table of Contents. Nothing else. Here are some solid options where that’s the case.

Heroic Table of Contents

The ability to edit/add/remove headers from the table of contents — even after it’s been automatically generated — is pretty powerful and unique to this plugin. It allows you to open and close it (optionally) as well, which is nice as a goal for these, as they should make the links useful rather than content that gets in the way. But beware that this puts you in the territory of enqueuing additional scripts as well as styles which may or may not be ideal or something you’re comfortable doing.

Screenshot of Heroic Table of Contents Block in WordPress
(Recommended by Deborah Edwards-Onoro)

Easy Table of Contents

This is not a Block Editor block! Instead, it only automatically inserts itself, either by content type or through an opt-in checkbox in a metabox.

I find it a little awkward that you can’t control where the Table of Contents goes with this plugin. Looks like it inserts itself near the top of posts, likely right after where the <!-- more --> is located.

Screenshot of Easy Table of Contents Block in WordPress

SimpleTOC

This is my favorite one.

I like this one because it doesn’t add any scripts or styles by default. It just makes a semantic HTML list out of the headers, links them up, and that’s it. That’s how I like to roll.

Screenshot of SimpleTOC Table of Contents Block in WordPress

LuckyWP Table of Contents

Lots of features, but I find it a bit awkward how it doesn’t have regular block controls. Instead, you get this entirely custom UI for changing the settings — and you can’t preview what it looks like in the block itself.

Screenshot of LuckyWP Table of Contents Block in WordPress

GutenTOC

Feels like this Table of Contents plugin embraces the spirit of the WordPress Block Editor quite well, but I find the settings a little awkward. The choices it offers don’t feel terrifically useful (like square bullets for the list? “15” space left?).

Screenshot of the GutenTOC Table of Contents plugin in WordPress.

Option 2: Wait for a Table of Contents feature to be baked into Core WordPress

As I write, there is an open pull request to enable a Table of Contents block in the Gutenberg plugin. Presumably, should that go well, it ultimately makes its way to core. That would be great if you ask me, but it doesn’t help solve the problem of needing a Table of Contents block right this second.

If this feature does drop, I’d lean heavily toward using it. Hopefully, I can do a search or query to find existing Table of Contents blocks on all posts, switch them over to use the native block, and remove whatever plugin I have in place.

Option 3: Use a Table of Contents Block that’s a sub-feature of another WordPress plugin

I would recommend against using a plugin that does a whole slew of things just because you want to use some small part of it. But hey, if it turns out you could use lots of things from the big plugin, it could be a bonus as far as managing fewer plugins overall.

Yoast SEO Premium

The free version of the Yoast SEO plugin doesn’t have it, but for only $99 per year, the Yoast SEO Premium plugin does. It has almost no features at all. You just add it as a block, and it pops in. You can edit the title or remove it — it’s almost like a “sub block.”

The list of links isn’t editable, but it does update in real-time as you change headings in the content, which is something most of the others I tested didn’t do. Super basic, no styling or features, but I kinda like that. I wouldn’t run Yoast for this one feature, especially for a paid premium, but if you’re using Yoast anyway (for the long haul), then you might as well go this route.

Screenshot of the Yoast SEO plugin’s table of contents block in WordPress.

Ultimate Addons for Gutenberg

This one is probably the classiest Table of Contents block I’ve come across. Again, I’m weary of using an all-in-one plugin for one specific feature, but the other features that are baked into this plugin are things you can use, then it’s a solid option.

Screenshot of the Ultimate Addons for Gutenberg Tablew of Contents plugin in WordPress.

Option 4: Roll your own DIY Table of Contents Block

Making blocks yourself isn’t out of the question! I’ve done it a few times with create-guten-block, though I’d probably reach for @wordpress/create-block these days. This puts you in JavaScript-land, so you’ll be parsing the content of the post with JavaScript, finding headings in the post content, and building things out from there. Kind of intermediate-to-advanced territory, I’d say. On one hand, it’s extra technical debt, and on the other, at least you have complete control since it’s your own code.

Since we’re focusing on building blocks, Advanced Custom Fields has a very powerful way of building custom blocks that brings that power back to PHP-land. That way, if you’re only concerned with building a Table of Contents from other heading blocks, the code gets a lot easier.

Bill Erickson has a post — “Access block data with PHP using parse_blocks() and render_block() — that ultimately gets into literally building a Table of Contents block. This gist he provides is a pretty useful reference for how to loop through blocks on a post and produce an HTML list.

Favorite?

If I was using Yoast SEO Premium on a site, I’d just use that one. If not, I’d go for SimpleTOC. That’s what we’ve done here on CSS-Tricks. Once the core feature drops (🤞), I’d make a rainy day project of moving all posts that currently use the Table of Contents plugin over to using the core WordPress block (assuming it turns out nice).