In this workshop, you’ll create a (non-interactive) “table of contents” display.

You can work by using the resources at the bottom of this page only (and your own research and skills), or by looking at the hints – or even by visiting the solution page and then going back and writing the code from memory.

Workshop context

  • In the previous workshop, you extracted an array of headings from an MDX blog post.
  • In future workshops, you’ll make the table of contents stick to the top of the viewport as you scroll, appear and disappear based on the width of the viewport, and add links from the table of contents headings to scroll to that heading in the post.
  • This project uses CSS modules for styling. You may prefer Tailwind CSS or some other styling system. I encourage you to use whatever works best for you!

Workshop goal

By the end of this workshop:

  • There should be a table of contents that displays the level 2 and 3 headings for the displayed post.
  • The table of contents should have a width of 18rem.
  • The table of contents should have a different background color from the rest of the page.
  • The top of the table of contents should be at the same height on the page as the first paragraph of the blog post.
  • The level 3 headings should be indented more deeply than the level 2 headings.
  • The “Blog hero” (title and disclaimer) and blog contents should maintain a maximum width of 44rem.

The end result should look approximately like this, but it’s fine if yours isn’t a “pixel perfect” rendition.

blog post with a table of contents on the right


Hint 1 I added a new ToC.tsx and ToC.module.css file within src/components/BlogPost. Why didn’t these get their own ToC folder? The ToC component is never going to be used outside BlogPost, so according to Josh W. Comeau’s recommended file structure , these don’t need to be exposed to the rest of the application.

Hint 2 You can find CSS custom properties for the site’s colors in src/app/globals.css .

Hint 3 I used a CSS Grid and grid areas to place the table of contents below the BlogHero and alongside the content.