Skip to content

Article with Table of Contents

Tailwind CSS long-form article layout with a sticky table of contents that highlights the current section and shows reading progress.

Live preview

Open in new tab

Code

A long-form article layout with a sticky table of contents, built with Tailwind CSS and a small vanilla JavaScript scroll spy. As the reader scrolls, the link for the section in view is highlighted and a progress bar shows how much of the article has been read. It suits documentation, guides, blog posts and knowledge base pages.

How it works

The root is .tat-article. It contains the article header and a two-column grid: the aside with nav.tat-toc on the left and article.tat-body (marked data-tat-body) on the right. On phones and tablets the table of contents is a white card above the text; from lg up the grid becomes lg:grid-cols-[15rem_minmax(0,1fr)] and the nav turns into a transparent sidebar with lg:sticky lg:top-6, so it stays visible while the content scrolls. The text uses a serif font for comfortable reading, with sans-serif headings.

Each .tat-link points to a section.tat-section by id. The script finds these pairs, then listens to scroll and resize (throttled with requestAnimationFrame). The last section whose top has passed ACTIVATION_LINE (30% of the viewport height) becomes current: its link gets aria-current="location", which the aria-[current=location]: variants style with a teal left border and bold text. When the page is scrolled to the bottom, the last section is selected even if it is short.

Clicking a link scrolls smoothly to the section, moves focus to its heading and updates the URL hash. The script also writes the reading percentage into the --tat-progress custom property of .tat-progress-bar and into aria-valuenow. Without JavaScript the links still work as normal anchor jumps, and scroll-margin-top in style.css keeps headings from touching the viewport edge.

Customization

  • ACTIVATION_LINE in script.js: raise it to 0.5 to switch sections later, lower it to switch as soon as a heading enters the top of the screen.
  • aria-[current=location]:border-teal-600 and aria-[current=location]:text-teal-800 on .tat-link: swap teal for another color to restyle the active item.
  • lg:grid-cols-[15rem_minmax(0,1fr)]: widen the sidebar to 18rem for longer section titles.
  • lg:top-6 on .tat-toc: increase it (and scroll-margin-top in .tat-section) when your site has a fixed header.
  • bg-[#faf7f2] on .tat-article: change the paper-like background, or use bg-white.
  • font-serif on .tat-body: replace with font-sans for a more technical look.
  • Remove the data-tat-progress block to hide the progress bar; the script skips it automatically.

Accessibility

The table of contents is a nav labelled by its "On this page" heading and uses an ordered list. The active link is exposed with aria-current="location", so screen readers announce which section is current, not only sighted users. After a click, focus moves to the target heading, so keyboard users continue reading in the right place. The progress bar uses role="progressbar" with aria-valuemin, aria-valuemax and a live aria-valuenow. Links have visible focus-visible outlines, and smooth scrolling and transitions are disabled under prefers-reduced-motion: reduce.

Usage notes

Add more sections by repeating the section.tat-section pattern and a matching .tat-link. Keep every id unique on the page.

Requirements

Add these to your page (already included in the download):

  • <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

The Tailwind browser build is for prototyping. In production, compile Tailwind with its CLI or your bundler.

Article with Table of Contents – Tailwind CSS content sections component screenshot
Article with Table of Contents · Tailwind CSS Content Sections

More Content Sections

Article Layout – Bootstrap 5 content sections preview

Article Layout

Bootstrap 5 long-form article layout with drop cap, wide figure, pull quote, author box and a sticky reading progress bar.