Tutorial: Scroll within a popup without scrolling the page

How to make a popup scroll-able without scrolling the underlying page :scroll:

Links: Demo and Editor.

Bear in mind this is a relatively “bare bones” version. There may be some nuances depending on how your page is laid out but this should get you most of the way conceptually!

So there are two aspects:

  1. Make the popup scroll its internal content (simples)
  2. Stop the main page behind it from scrolling (bit trickier)

:one: Part One: Scrolling the popup

  1. Add your popup, and give it a unique ID

  2. Add an HTML element to the page and insert the following inside of “style” tags:

   top:0px !important;
  	max-height: 100vh !important;
  	overflow-y:scroll !important;


Note, the height of the popup should not exceed the page height. Bubble is a bit funny about this and the scroll will not work if the end of the popup is past the “fold” i.e. past the initial view on page load. Setting top to 0 sticks the popup to the top, and making the max-height “100vh” ensures it does not expand beyond the bottom of the screen.

If you want the popup to be more in the middle of the screen change “max-height” to 90vh, and “top” to 5vh (as is the case in the demo)

That’s the basics of it! Test it out. It should scroll internally as long as the content is taller than the popups height.

:two: Part Deux: Making the underlying page not scroll

So the basic idea is to hold the background fixed while the popup is open so that is cannot scroll. There’s a few ways to do it and I’ve burnt a lot of midnight oil in the past to find a solution that works for the way Bubble renders pages. Here it is.

Firstly, you will need the “Toolbox” plugin which contains a “Run Javascript” action. It’s a free plugin created by @mishav

  1. Add an ID to your page

  2. When the popup is opened: Inject some JS when the popup is opened. Crucial here is that the script runs before the popup is actually opened in the workflow. See below for workflow and JS.

savedScrollY = window.scrollY;
let x = document.getElementById("myPage"); 
x.style.position = "fixed"; 
x.style.top = -savedScrollY+"px";
  1. When the popup is closed: Run another JS script as follows.
let x = document.getElementById("myPage");
x.style.position = "absolute";
x.style.top = "";
window.scrollBy(0, savedScrollY);

Et voila! You should have a popup that scrolls internally without the page behind it moving.

Live long and prosper, friends. :vulcan_salute:


PS. Scrollbars: Default scrollbars are hideous. They will naturally appear when you’re forcing an element to scroll like this. I use a great little plugin called Sweet Scrollbar from @Yinka . Follow the setup in the demo to hide your scrollbars. If you must have scrollbars, this plugin will at least make them look prettier.

PPS: Mobile: There can be some quirks when displaying on mobile due to the extra height added by the mobile browser’s navigation bar. This can be worked around however.


Brilliant, thanks mate!



This is brilliant, thanks for sharing this!

I used this variation of your technique for my use case that doesn’t style the popup. This also works when the popup is inside a reusable. I’ve tested in Chrome, Mozilla, Safari, on desktop & mobile, and a wrapped app on ios. :+1:

I thought I’d share it here for anyone looking for something similar. Thanks again for sharing, I wouldn’t have been able to implement this version without yours. :vulcan_salute:


Thans @andy.i - missed that! Added in now.



Hey @robhblake, Thank you for sharing this. I was stuck with this problem and found your post with the perfect solution.


@andy.i you are a superstar!

Also thanks to @robhblake for the original idea!


Is it different with the new editor ?

Thanks, @robhblake this helped a Lot!!


Hi @andy.i

Thanks for sharing this. I have tested this and it works great with a popup.

I am attempting to get this to function with a floating group, and I am seeing that on a mobile device the javascript running will cause the page height to decrease so that there is a large gap at the bottom of the page. When using a popup, that gap closes and the page height is back to normal, but when using a floating group, that gap doesn’t close and the page height remains with that gap.

I’ve tested this without showing the floating group or popup and the same issue occurs in that the javascript runs and causes a gap between bottom of content and page.

This happens when the user has scrolled the original text, then clicks the text to initiate the javascript workflow to run. As that javascript runs the height seems to resize and the gap appears.

This does not happen if the user had not scrolled the page at first.

Do you know of anything that could be done to make sure the floating group will cause the same expansion of the page the popup does?

Thanks mate, this tips saved my project!

hi there! First, thank you very much, this helped a lot. Second, I did all what you said, but after it display some extra height at the top and bottom. How can I take that away??

Great method, will definitely use it. The way I do is:

On the page, set condition

And this in the html



Hello! Thank you very much for this post, it helped me a lot. Is it possible that you upload another post that includes the solution to the problems that are generated in mobile phones? I’m making an app and even though I did everything you said, the browser keyboard adds an extra space that I don’t know how to remove. If you know how to do it you would help me a lot!!! Thanks in advance

Very cool thanks man! Life saver :slight_smile:

This is awesome thanks so much for sharing this!

Has anyone figured a way to make a “close button” float on a pop-up so when scrolling it stays visible?

Thanks @robhblake for the original post - as alluded to, mobile implementations can be unpredictable! :slight_smile:

To make this work seamlessly on mobile (as well as desktop) and account for dynamically changing mobile browser nav/search bar behaviour you can modify the original code to the following:

HTML element script stays the same:

top:0px !important;
max-height: 100vh !important;
overflow-y:scroll !important;

Or modify to maintain the default behaviour of popups for larger screen sizes:

@media (max-width: 767px) {
#popup {
top: 0px !important;
max-height: 100vh !important;
overflow-y: scroll !important;

JS action for opening popup:

// Capture the current scroll position
savedScrollY = window.scrollY;

let x = document.getElementById(“page”);
x.style.position = “fixed”;
x.style.top = -savedScrollY + “px”;

JS action for closing popup:

let x = document.getElementById(“page”);

// Reset the page’s style properties
x.style.position = “”;
x.style.top = “”;

// Adjust for potential changes in viewport height due to mobile browser navigation bar
let adjustedScrollY = savedScrollY;
if (window.innerHeight !== window.visualViewport.height) {
adjustedScrollY += (window.innerHeight - window.visualViewport.height);

window.scrollTo(0, adjustedScrollY);

Honestly this method has alot of jank and can give errors when not implemented properly.

It’s easier to useoverscroll-behavior: none.

Yea plus I’m pretty sure on the new responsive we just uncheck “Fit height to content” and check “Allow scrolling when content overflows” (on popup or in a group inside popup)? :grinning_face_with_smiling_eyes:

This very much depends on your implementation and chosen UX - these are only examples to be worked from. For my implementation the outcome based on the above is perfect and allows much more flexibility that the out-of-the-box options.

In a PWA you might want a popup to behave differently under different conditions to give the user the feel of an app or a desktop website in different contexts. All implementations do have trade-offs - it all depends what you want to achieve.

GREAT stuff. only part deux was enough for my situation.

once i have an infinite scroll behavior in my app, it wasnt nice to have it scrolling with a popup open, as the popup was getting out of focus and turning things messy.

now it works as a charm! THX!