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.
Prerequisites
- 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
Create a fixed progress bar at the top of the page
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.
Add a custom state to store the scroll percentage
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.
Add JavaScript to track scroll position
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.
1<script>2window.addEventListener('scroll', function() {3 var scrollTop = window.pageYOffset || document.documentElement.scrollTop;4 var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;5 var scrollPercent = (scrollTop / docHeight) * 100;6 var bar = document.getElementById('progress-bar');7 if (bar) {8 bar.style.width = scrollPercent + '%';9 }10});11</script>Expected result: The progress bar width updates smoothly in real time as the user scrolls through the page content.
Add smooth transitions to the progress bar
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.
1<style>2#progress-bar {3 transition: width 0.1s ease;4}5</style>Expected result: The progress bar fills smoothly as the user scrolls, with no visual jumping between positions.
Test and adjust for different content lengths
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 working example
1<!-- READING PROGRESS INDICATOR -->2<!-- Place this HTML element anywhere on the page -->34<style>5 #progress-bar {6 transition: width 0.1s ease;7 }8</style>910<script>11 // Track scroll position and update progress bar12 window.addEventListener('scroll', function() {13 var scrollTop = window.pageYOffset14 || document.documentElement.scrollTop;15 var docHeight = document.documentElement.scrollHeight16 - document.documentElement.clientHeight;17 18 if (docHeight <= 0) return; // Prevent division by zero19 20 var scrollPercent = Math.min(21 (scrollTop / docHeight) * 100,22 10023 );24 25 var bar = document.getElementById('progress-bar');26 if (bar) {27 bar.style.width = scrollPercent + '%';28 }29 });30 31 // Reset on page load32 window.addEventListener('load', function() {33 var bar = document.getElementById('progress-bar');34 if (bar) {35 bar.style.width = '0%';36 }37 });38</script>3940<!--41 BUBBLE SETUP:42 1. Floating Group: top, full width, height 4px43 2. Inner Group: id='progress-bar', height 100%,44 bg #3B82F6, width starts at 0%45 3. Place this HTML element anywhere on the page46-->Common mistakes when creating a reading progress indicator in Bubble.io: Step-by-Step Guide
Why it's a problem: Placing the progress bar inside a scrolling container instead of a Floating Group
How to avoid: Always use a Floating Group fixed to the top of the page for the progress bar container
Why it's a problem: Setting the progress bar to a fixed width instead of percentage-based
How to avoid: Use the JavaScript scroll calculation to set the width as a percentage of the viewport width
Why it's a problem: Not handling the case where page content is shorter than the viewport
How to avoid: 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
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to add a reading progress indicator to my Bubble.io blog pages. The bar should sit at the top of the page and fill as the user scrolls through the article. How do I set this up with JavaScript and Bubble elements?
Add a thin progress bar at the top of my blog post page that fills from left to right as the reader scrolls through the article. Use a Floating Group and JavaScript to track scroll position.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation