Skip to content

How to add a table of contents to a Shopify blog post (2026)

Ahoi Apps team · Updated · 6 min read · How we test

Quick answer

Shopify's blog editor has no table of contents block. Type one by hand with anchor links (fine for one or two posts), add a short script to your blog post template that builds the list from your headings (free, needs theme access), or install an app that does it from the theme editor on every post, product or page (from free; Auto TOC is ours). Under 800 words, skip all three.

Why add a table of contents?

Two reasons, one for readers and one for Google.

Readers of a long post came for one part of it. A linked list at the top lets them jump there instead of scrolling, and a reader who finds their answer in ten seconds is more likely to read the rest, click a product, or come back. On a phone, where a 2,000-word guide is forty screens, this matters more.

Google sometimes shows links to sections of a page under a search result (“Jump to”). Its sitelinks guidance asks for informative headings and concise, relevant link text (Google on sitelinks), and a table of contents is exactly that: headings with anchors and in-page links that point to them. It doesn’t rank the post, but it can make the result bigger and send people to the right section.

What it won’t do: fix a thin post. A table of contents on three short paragraphs is a list of three links above a page that fits on one screen. We’d leave it off anything under about 800 words.

Three ways to add one, in order

1. By hand, in the blog editor

Best for one or two long posts, or to see whether readers use it before you set up anything.

Shopify’s rich text editor can insert links and lets you edit the HTML (Shopify Help Center). The idea: give each heading an id, then put a list of links to those ids at the top.

  1. Open the post, click the <> button to switch the editor to HTML.
  2. Find each heading and add an id: <h2 id="choose-a-theme">Choose a theme</h2>. Use lowercase, hyphens, no spaces.
  3. At the top of the post, add the list:
Blog post HTML
<nav class="toc" aria-label="Table of contents">
<p><strong>In this guide</strong></p>
<ol>
  <li><a href="#choose-a-theme">Choose a theme</a></li>
  <li><a href="#set-up-collections">Set up collections</a></li>
  <li><a href="#write-product-pages">Write product pages</a></li>
</ol>
</nav>
  1. Switch back to the visual editor and save. Click each link in the preview.

Limits: every new heading means editing the list again, and the editor sometimes strips ids when you reformat a heading. It also looks the way your theme styles any list, which is usually fine and sometimes ugly. For a blog you post to weekly, go to option 2 or 3.

2. A script in the blog post template

Best for stores with theme access and a developer, or a merchant who doesn’t mind the code editor. Free, and it works on every post from now on.

The script runs on the article page, finds the headings in the post, gives each an id, and builds the list. On an Online Store 2.0 theme (Dawn and everything since) you add it as a Custom Liquid section, so it survives theme updates.

  1. In the admin, open Online Store › Themes › Customize, then switch the page selector to Blog posts › Default blog post.
  2. Click Add section › Custom Liquid. Dawn’s blog post section has no Custom Liquid block, so the code sits in its own section below it; the script moves the list to the top of the article text.
  3. Paste this into the Custom Liquid field:
Custom Liquid section
<nav class="toc" aria-label="Table of contents" hidden>
<p class="toc__title">In this article</p>
<ol class="toc__list"></ol>
</nav>
<script>
(function () {
  var article = document.querySelector('.article-template__content, .rte');
  var nav = document.querySelector('.toc');
  if (!article || !nav) return;
  var headings = article.querySelectorAll('h2, h3');
  if (headings.length < 3) return;
  var list = nav.querySelector('.toc__list');
  headings.forEach(function (h, i) {
    if (!h.id) {
      h.id = h.textContent.trim().toLowerCase()
        .replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'section-' + i;
    }
    var li = document.createElement('li');
    li.className = 'toc__item toc__item--' + h.tagName.toLowerCase();
    var a = document.createElement('a');
    a.href = '#' + h.id;
    a.textContent = h.textContent;
    li.appendChild(a);
    list.appendChild(li);
  });
  article.insertBefore(nav, article.firstChild);
  nav.hidden = false;
})();
</script>
<style>
.toc { border: 1px solid currentColor; padding: 1rem 1.25rem; margin: 0 0 2rem; }
.toc__title { margin: 0 0 .5rem; font-weight: 600; }
.toc__list { margin: 0; padding-left: 1.25rem; }
.toc__item--h3 { margin-left: 1rem; }
</style>
  1. Save, open a post with at least three headings, and check the links. If the list doesn’t show, your theme’s article content uses a different class: right-click the post text, choose Inspect, and replace .article-template__content, .rte with the class you see.

Three things the script does on purpose: it only builds a list when there are three or more headings, so short posts stay clean; it keeps ids you set by hand; and it marks H3s so you can indent them.

Limits: it’s JavaScript, so the list isn’t in the HTML Google first downloads. Google renders JavaScript and the anchors are on the headings either way, but if you want the list in the source, option 1 or an app that renders through Liquid is the way. On a vintage (pre-2.0) theme there’s no Custom Liquid section; paste the same code into sections/article-template.liquid above the content and accept that a theme update may remove it. And every style change is a code change.

3. An app

Best for anyone who wants it on every blog post, and on product, collection or store pages too, with styling in the theme editor and no code.

A table of contents app is a theme app block: you add it in the theme editor, pick colors, numbering, position and which heading levels count, and it builds the list on every page of that type. Free plans usually cover blog posts; product and collection pages are paid.

Ours is Auto TOC: Blog SEO & Nav: free on blog posts, $1.99/month or $39.90 once for products, collections and pages, with a pick of heading levels H1 to H6, show on selected articles or all, and support for Online Store 2.0 and vintage themes. We compared it with four others, two of which have mobile features ours doesn’t, in best table of contents apps for Shopify. Read that before you pick; the honest answer depends on how your readers arrive.

Step by step: what every table of contents needs

Whichever option you choose, check these on one post before rolling it out:

  1. Headings are real headings. The editor lets you make text bold and large; that’s not an H2. Use the paragraph style menu so the post has H2s for sections and H3s under them. No table of contents can read bold text.
  2. One H1, which is the title. The theme sets it. Don’t add another in the post.
  3. Anchors land below a fixed header. If your theme has a sticky header, a jump lands under it. Add html { scroll-padding-top: 80px; } (your header’s height) in the theme’s CSS, or in the <style> block above.
  4. The list is near the top, after the intro. Readers want the quick answer first, then the map.
  5. Phone check. Open the post on a phone. If the list is longer than the screen, cut it to H2s only, or use a collapsible one.
  6. Click every link. Headings with the same text get the same id and only the first works. Rename one of them.

Mistakes we see most

  • A list with one or two items. Needs at least three to be worth the space. The script above enforces it; check whether your app has a minimum setting.
  • Every H4 included. Twenty links is a wall. H2s, maybe H3s, nothing deeper.
  • Headings written for the list, not the reader. “Step 3” tells nobody anything in a table of contents. “Submit the sitemap in Search Console” does.
  • Sticky header hides the heading after a jump. See step 3 above; it’s one CSS line and most stores never add it.
  • Two tables of contents. A theme that already has one (some blog-focused themes do) plus an app gives two. Check the article template before you install anything.
  • Expecting a ranking jump. You’ll get jump links in results and better engagement; you won’t move from page 3 to page 1 because of a list.

FAQ

Does Shopify have a built-in table of contents for blog posts?

No. The blog editor has headings, lists and links, but no table of contents block. Some third-party themes include one in the article template; check yours in the theme editor under Blog posts.

Can I add a table of contents without an app?

Yes: by hand with anchor links in the HTML editor, or with a small script in a Custom Liquid section on the blog post template. Both are above.

Does a table of contents help Shopify SEO?

It helps Google show jump links under your result and keeps readers on the page longer. It doesn't rank the post on its own; the content does.

Does it work on product pages?

With a script, only if you add it to the product template too and your descriptions have headings. With an app, usually on a paid plan.

Will a table of contents slow down my store?

A script of forty lines or a theme app block doesn't. Measure in Lighthouse before and after if you want to be sure.

Why do my anchor links jump to the wrong place?

A sticky header. Add scroll-padding-top equal to the header's height to the html element in your CSS.

Do I need JSON-LD or schema for a table of contents?

No. Google reads the anchors and headings in the HTML. Some apps add JSON-LD anyway; it doesn't hurt and it isn't required.

Related