Skip to content

Reading Progress Bar

Sticky Tailwind CSS reading progress bar with a gradient fill, clickable chapter markers, current section label, minutes left and a circular back-to-top indicator.

Live preview

Open in new tab

Code

A reading progress bar for long articles, built with Tailwind CSS and a small vanilla JavaScript controller. A sticky dark header shows a glowing gradient bar that fills as you read, clickable chapter markers, the current section name, an estimate of the minutes left and a circular percentage button that jumps back to the start. Use it on blog posts, documentation pages and long-form guides.

How it works

The root is .tsp-reader. Inside it, the sticky .tsp-header holds the section label (data-tsp-section), the article title, the time estimate (data-tsp-time), the .tsp-ring button (data-tsp-top) and the .tsp-track with the .tsp-bar progress element. The text being measured is the element marked data-tsp-article, and every heading marked data-tsp-heading becomes a chapter.

The script initializes each .tsp-reader on DOMContentLoaded. It measures where the article starts (its top meeting the bottom of the header) and where it ends (its bottom reaching the bottom of the viewport), so progress reflects the article rather than the whole page and reaches 100% even when a footer follows. A passive scroll listener schedules one requestAnimationFrame update, which writes the value from 0 to 1 into the --tsp-progress custom property on the root. style.css turns that single number into transform: scaleX() on .tsp-bar and a stroke-dashoffset on the .tsp-ring-value circle, so no layout is recalculated while scrolling.

For every heading with an id, the script appends an a.tsp-tick marker to the track at the heading's position; markers turn light once passed (.is-passed) and scroll to their section when clicked. Positions are re-measured on resize, on load and through a ResizeObserver on the article.

Customization

  • data-tsp-wpm on .tsp-reader: the reading speed used for the minutes-left estimate; lower it to 180 for technical content.
  • from-lime-300 via-emerald-400 to-cyan-400 on .tsp-bar: swap the gradient stops, for example to from-fuchsia-500 to-orange-400.
  • h-1.5 on .tsp-track: use h-1 for a hairline bar or h-2.5 for a bolder one.
  • box-shadow in the .tsp-bar rule in style.css: remove it to drop the glow on light backgrounds.
  • --tsp-speed on .tsp-reader in style.css: the smoothing transition of the bar and ring; set 0ms for an instant response.
  • data-tsp-heading: remove it from a heading to hide its chapter marker, or add it to h3 elements for finer chapters.
  • Delete the data-tsp-time paragraph or the .tsp-ring button for a minimal bar; the script skips missing parts.

Accessibility

.tsp-bar has role="progressbar" with aria-label="Reading progress", aria-valuemin, aria-valuemax, and aria-valuenow plus aria-valuetext updated as the percentage changes. The ring button has a descriptive aria-label, while its SVG and number are aria-hidden. Chapter markers are real links with aria-label="Jump to section: ...", reachable by keyboard and shown with a lime focus outline. Under prefers-reduced-motion: reduce the transitions are removed and jumps scroll instantly instead of smoothly.

Usage notes

The header uses sticky, so it stays within its own .tsp-reader; several readers on one page each track their own article. Keep heading id values unique across instances.

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.

Reading Progress Bar – Tailwind CSS scroll animations component screenshot
Reading Progress Bar · Tailwind CSS Scroll Animations

More Scroll Animations

Scroll Reveal Animations – Pure CSS scroll animations preview

Scroll Reveal Animations

Elements fade, slide, zoom or flip into view on scroll using IntersectionObserver and data-sr attributes, with stagger delays and reduced-motion support.