Free WordPress Plugin
Reading Progress Bar & Table of Contents for WordPress
Reading Progress & Table of Contents adds a lightweight reading progress bar and an automatic list of sections to long WordPress posts and pages. Readers see how far they have left, move straight to the section they want, and keep their place as they scroll.
It works the moment you activate it, inherits your theme’s colours in light and dark mode, and skips the repeated layout calculations that make some scroll-based plugins more expensive than they need to be.
It works the moment you activate it, inherits your theme’s colours in light and dark mode, and skips the repeated layout calculations that make some scroll-based plugins more expensive than they need to be.
Compatible With
How it earns it’s place
Easy to Navigate
A list of every section, and a bar that shows how far there is to go. Readers can see the shape of a page and jump straight to the part they need.
Fast By Design
No jQuery, and no constant interrogation of the page while someone scrolls. The speed section below shows the working.
Matches Your Theme
Colours come from your active theme, dark mode included. On most sites, there is nothing to restyle before it fits.
WCAG Accessibility Focus
The rail opens on keyboard focus, the current section is marked in the page’s markup for screen readers, and custom colour choices are checked for readable contrast.
Choose your layout
Two ways to show it. Pick the one that suits the page.
The Side Rail
A slim column of markers pinned to one side. It stays out of the way until a reader hovers over it, then opens into the full list. On mobile it switches to the horizontal bar.
Best for: long-form editorial pages where the contents should stay out of the way.
The Bar
A strip pinned to the top or bottom of the window, with the section links running alongside a progress fill.
Best for: persistent visibility and conventional article layouts.
Made to match your brand
Set your colours once
Follow your theme’s own colours, pick from its palette, or set exact ones of your own, each with its own opacity. Choose custom colours and a live contrast check warns you (never stops you) when a text-and-background pairing gets hard to read.
Switch a visitor to dark mode and the colours follow, because they are composed in the browser rather than baked in when the page renders.
Switch a visitor to dark mode and the colours follow, because they are composed in the browser rather than baked in when the page renders.
How it stays fast
For readers who open dev tools
Ask a browser where an element sits, just after you have changed the page, and it has to work out the layout before it can answer. Once, that is nothing. Ask it dozens of times a second while someone scrolls, which is how a fair few progress bars work, and the browser keeps recalculating. A reader feels that as a scroll that never quite glides.
This plugin measures position once: on load, and again after a settled resize. Those figures stay in memory. The scroll listener that runs afterwards is passive, and during a normal scroll it reuses those measurements rather than querying the layout again, setting one CSS transform per frame through
Check it yourself. Record a scroll in the browser’s Performance panel and watch the main thread. During an ordinary scroll, you should not see repeated layout work caused by the bar.
This plugin measures position once: on load, and again after a settled resize. Those figures stay in memory. The scroll listener that runs afterwards is passive, and during a normal scroll it reuses those measurements rather than querying the layout again, setting one CSS transform per frame through
requestAnimationFrame. The current section is tracked with an IntersectionObserver, which keeps that work out of the scroll handler.Check it yourself. Record a scroll in the browser’s Performance panel and watch the main thread. During an ordinary scroll, you should not see repeated layout work caused by the bar.
Put it where you want
Auto-insert covers most sites, if it doesn’t:
- Turn it on for one page. Add the TOC & Progress block anywhere in the editor. The component still docks to the window; the block is an instruction to show it on that page, not a way to position it.
- Outside the block editor. Use the
[reading_progress_toc]shortcode (short form) in the Classic Editor or a page builder. - Define the sections yourself. Add TOC Anchor blocks where you want entries. Once a page has one anchor, the plugin uses your anchors instead of reading headings, labels and all.
- Decide per post. A Reading Progress & Contents panel in the sidebar sets Always show or Never show for that post alone.
The settings page
Four tabs, and the defaults work untouched.
- General. Automatic insertion, minimum section count, heading levels, post types, exclusions, content detection, and structured data.
- Placement. Bar or rail, link alignment, fill position, which edge it docks to, and the header offset.
- Appearance. Pill or plain-text links, inherited or custom font sizes, and pill spacing.
- Colours. Follow the theme, use its palette, or set custom colours and opacity, with the live contrast check.
Plugin Features
- Automatic table of contents, from H2 down to H6
- Reading progress bar
- Current-section highlighting
- Horizontal bar and side-rail layouts
- Theme colour matching, with dark mode
- Colour source: follow, palette, or custom, each with opacity
- Live in admin WCAG contrast checker on custom colours
- Alignment: start, centre, or end
- Dock at the bottom, or below the header, with an offset
- Pill or plain-text links
- Custom font sizes for desktop and mobile
- TOC Anchor block for sections that are not headings
- Block, shortcode, and per-post control
- Optional ItemList structured data
- Rank Math table-of-contents recognition
- WPML and Polylang, with a translation template
- Right-to-left support (RTL)
- ARIA-current on the active link, for screen readers
Compatibility
- Themes: designed for standard WordPress themes, with automatic content and header detection, and a custom content selector for unusual layouts.
- Editors: works in the block editor and the Classic Editor, and anywhere your content runs through WordPress’s standard post content.
- Rank Math: registers as a recognised table of contents for Rank Math’s content analysis.
- Yoast and AIOSEO: runs alongside either. Its optional ItemList markup is output independently of their page schema.
- WPML and Polylang: manual anchor labels can be translated, and post exclusions apply across translated versions.
- Requirements: WordPress 6.0 or later, PHP 7.4 or later.
- Licence: GPL. Free to inspect, modify and redistribute.
Questions & Answers
Can I turn it off on one post?
Yes. Each post has a sidebar panel. Never show switches it off there, Always show forces it on, and neither touches your global settings.
Can I define the sections myself?
Yes. Add TOC Anchor blocks where you want entries. One anchor on a page switches it from reading headings to using your anchors.
What happens on mobile?
The side rail switches to the horizontal bar. The bar behaves the same everywhere.
Does it change my content?
It adds an
id to each heading it links to, in the rendered page, and appends its own markup. Your saved content is left alone.Will it improve my search rankings?
It makes the page easier to navigate and can add optional ItemList markup describing its sections. Neither guarantees a ranking change or a particular search-result feature.
Does it collect any data?
No. Nothing is tracked, and nothing is sent anywhere.
Can I restyle it?
Yes. The colours and spacing are CSS custom properties, so a few lines of CSS will re-skin it without editing the plugin.
Does it need JavaScript?
The section links are ordinary anchors and work without it. The progress fill, the current-section highlight, and the rail opening and closing all need JavaScript.