# How to create a reading progress indicator in Bubble.io: Step-by-Step Guide

- Tool: Bubble
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Add a reading progress indicator to your Bubble app that shows a horizontal bar at the top of the page filling as the user scrolls through article content. This tutorial covers tracking scroll position with JavaScript, updating a custom state, and dynamically resizing a progress bar element so readers always know how far they have read.

## Overview: Creating a Reading Progress Indicator in Bubble

This tutorial shows you how to add a scroll-based reading progress bar to your Bubble blog or article pages. The bar sits at the top of the page and fills from left to right as the reader scrolls down. You will use a small JavaScript snippet in an HTML element to detect scroll position, pass it to a Bubble custom state, and use that state to dynamically set the width of a colored bar element.

## Before you start

- A Bubble account with a page containing long-form content
- Basic familiarity with Bubble's Design tab
- Understanding of custom states in Bubble

## Step-by-step guide

### 1. Create a fixed progress bar at the top of the page

On your article or blog post page, add a Floating Group element at the top of the page. Set it to float relative to Top and make it full width with a height of 4 pixels. Set the background to transparent or a light grey. Inside this Floating Group, add a Group element (the progress fill). Set this inner group's height to 100 percent, background to a bold color like blue (#3B82F6), and align it to the left. Set its width to 0 percent initially. Give this inner group an ID of progress-bar in the element's settings.

> Pro tip: Keep the progress bar height between 3 and 5 pixels for a subtle effect that does not distract from the content.

**Expected result:** A thin bar appears fixed at the top of the page, initially with zero width.

### 2. Add a custom state to store the scroll percentage

Click on the page element itself (not any child element). In the Property Editor, go to the element's custom states and create a new state called Scroll Percent of type number with a default value of 0. This state will be updated by JavaScript as the user scrolls and will drive the progress bar width.

**Expected result:** A Scroll Percent custom state exists on the page element with a default value of 0.

### 3. Add JavaScript to track scroll position

Add an HTML element to the page (it can be placed anywhere since it will be invisible). Paste a script that listens for the scroll event on the window. The script calculates the scroll percentage as: (how far the user has scrolled) divided by (total scrollable height minus the viewport height), multiplied by 100. It then updates the progress bar width directly using the element ID. This approach avoids the overhead of constantly updating a custom state on every scroll pixel.

```
<script>
window.addEventListener('scroll', function() {
  var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
  var scrollPercent = (scrollTop / docHeight) * 100;
  var bar = document.getElementById('progress-bar');
  if (bar) {
    bar.style.width = scrollPercent + '%';
  }
});
</script>
```

**Expected result:** The progress bar width updates smoothly in real time as the user scrolls through the page content.

### 4. Add smooth transitions to the progress bar

Add another HTML element (or append to the existing one) with a style tag that targets the progress bar ID. Set a CSS transition on the width property so the bar animates smoothly rather than jumping between positions. A transition of 0.1 seconds with ease timing provides a responsive feel without lag.

```
<style>
#progress-bar {
  transition: width 0.1s ease;
}
</style>
```

**Expected result:** The progress bar fills smoothly as the user scrolls, with no visual jumping between positions.

### 5. Test and adjust for different content lengths

Preview your page and scroll through the content. The bar should read 0 percent at the top and reach 100 percent when you scroll to the very bottom. If the bar reaches 100 percent too early, check that the HTML element is placed within the page content flow (not inside a group that limits its height). If the page has a fixed-height container, you may need to modify the script to track the container's scroll position instead of the window. Test on both desktop and mobile viewports.

**Expected result:** The progress bar accurately shows 0 percent at the top and 100 percent at the bottom of the content on all screen sizes.

## Complete code example

File: `HTML element — complete reading progress indicator`

```html
<!-- READING PROGRESS INDICATOR -->
<!-- Place this HTML element anywhere on the page -->

<style>
  #progress-bar {
    transition: width 0.1s ease;
  }
</style>

<script>
  // Track scroll position and update progress bar
  window.addEventListener('scroll', function() {
    var scrollTop = window.pageYOffset
      || document.documentElement.scrollTop;
    var docHeight = document.documentElement.scrollHeight
      - document.documentElement.clientHeight;
    
    if (docHeight <= 0) return; // Prevent division by zero
    
    var scrollPercent = Math.min(
      (scrollTop / docHeight) * 100,
      100
    );
    
    var bar = document.getElementById('progress-bar');
    if (bar) {
      bar.style.width = scrollPercent + '%';
    }
  });
  
  // Reset on page load
  window.addEventListener('load', function() {
    var bar = document.getElementById('progress-bar');
    if (bar) {
      bar.style.width = '0%';
    }
  });
</script>

<!--
  BUBBLE SETUP:
  1. Floating Group: top, full width, height 4px
  2. Inner Group: id='progress-bar', height 100%,
     bg #3B82F6, width starts at 0%
  3. Place this HTML element anywhere on the page
-->
```

## Common mistakes

- **Placing the progress bar inside a scrolling container instead of a Floating Group** — The bar scrolls away with the content instead of staying fixed at the top of the viewport Fix: Always use a Floating Group fixed to the top of the page for the progress bar container
- **Setting the progress bar to a fixed width instead of percentage-based** — A fixed pixel width does not adapt to different content lengths and will not accurately represent scroll progress Fix: Use the JavaScript scroll calculation to set the width as a percentage of the viewport width
- **Not handling the case where page content is shorter than the viewport** — If there is no scrollable content, the division by zero in the scroll calculation causes errors or NaN values Fix: Add a guard clause checking that docHeight is greater than zero before calculating the percentage

## Best practices

- Keep the progress bar thin (3-5 pixels) so it does not distract from content
- Use a Floating Group fixed to the top of the viewport for consistent positioning
- Add a CSS transition for smooth animation instead of jumpy width changes
- Include a guard clause for pages with content shorter than the viewport
- Use a high-contrast color for the progress bar that matches your brand
- Test on both desktop and mobile since scrolling behavior differs between devices

## Frequently asked questions

### Can I change the color of the progress bar dynamically?

Yes. Modify the JavaScript to change the bar's background color based on the scroll percentage. For example, change from blue to green as the reader progresses past 50 percent.

### Does this work on mobile browsers?

Yes. The scroll event fires on mobile browsers. However, some mobile browsers have address bar behavior that affects the total scrollable height. The Math.min guard in the script ensures the bar never exceeds 100 percent.

### Will this affect my app's performance?

The scroll event fires very frequently. The script is lightweight (just a division and a style update), so the performance impact is minimal. Avoid adding database operations or complex calculations inside the scroll handler.

### Can I show the percentage as a number alongside the bar?

Yes. Add a Text element inside the Floating Group. Modify the JavaScript to also update a Bubble custom state (using bubble_fn_scrollPercent for Toolbox plugin) so the Text element can display the number dynamically.

### Can RapidDev help add advanced reading features?

Yes. RapidDev can help you build reading features like estimated read time, bookmarking positions, and progress saving so returning readers pick up where they left off.

### How do I hide the progress bar on non-article pages?

Only add the Floating Group with the progress bar to article pages, or use a Reusable Element that you place only on pages where reading progress makes sense.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/create-a-reading-progress-indicator-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/create-a-reading-progress-indicator-in-bubble
