I thought I had seen every way a UI could break until I spent a Tuesday debugging dropdowns in scrollable containers. The setup is almost always the same: a data table inside a scrollable div, with an action menu on every row. It behaves perfectly in isolation, then you ship it and the menu either gets clipped or drifts away while the user scrolls. That is not a random glitch. Three separate browser systems are working against you at once.
Why dropdowns in scrollable containers break
It usually starts when you reach for z-index: 9999 and absolutely nothing happens. The bug keeps coming back because overflow, stacking contexts and containing blocks get treated as three unrelated problems. When they meet, your absolutely positioned menu is still trapped inside the parent’s overflow: hidden or auto.
Set a non-visible overflow on an element and the browser clips anything that reaches past its bounds. Your dropdown gets cut off by an ancestor that is not even its containing block. Escaping that container takes more than a big stacking number.
The naive approach, and why it fails
The assumption is that position: absolute lets an element float above everything. It doesn’t. Any ancestor with overflow: auto or scroll becomes a clipping boundary. The broken structure normally looks like this:
.scroll-container {
overflow: auto;
height: 300px;
/* This boundary will clip the dropdown no matter the z-index */
}
.dropdown {
position: absolute;
top: 100%;
z-index: 9999;
}
Modern fixes for WordPress developers
Inside the Gutenberg editor or a busy WooCommerce dashboard you have a few options, and now that modern CSS is finally safe to use, they are better than what we had five years ago.
1. The portal pattern
In React environments like the WordPress block editor, createPortal is the standard fix. Move the dropdown markup to the end of document.body and it leaves the scrollable container’s clipping context behind. The trade is that you now work out the coordinates yourself with getBoundingClientRect().
2. CSS anchor positioning
CSS anchor positioning is where the web is heading. You declare the relationship between a trigger and a menu in CSS, and the browser handles the coordinates plus the flip when the menu runs into the viewport edge.
.trigger {
anchor-name: --action-menu;
}
.dropdown-menu {
position: absolute;
position-anchor: --action-menu;
top: anchor(bottom);
left: anchor(left);
/* Automatically flips if it overflows the viewport */
position-try-fallbacks: flip-block;
}
I go further into this in my post on modern CSS features including anchor positioning.
Where the Popover API helps
The HTML Popover API works in every modern browser now. It renders the element in the browser’s top layer, which sits above everything else, your scroll containers included. Positioning is still your job, so you need JavaScript or anchor positioning for that, but the clipping problem disappears.
<button popovertarget="my-menu">Open Actions</button>
<div id="my-menu" popover="manual" role="menu">
<!-- Menu Content -->
</div>
If dropdowns in scrollable containers are eating your dev hours, hand them to me. I have been wrestling with WordPress since the 4.x days and seen most of the layout shifts it can produce.
One last thing about accessibility
Whichever method you pick, the moment you move an element to the body or the top layer, managing focus becomes your job. Keep aria-controls and aria-expanded in sync with the state. If a keyboard user cannot reach your fixed dropdown, it isn’t fixed, it is just differently broken.
Debugging dropdowns in scrollable containers taught me to read the DOM tree instead of collecting hacks. Once you can see where the clipping boundaries sit, the fix stops being a guess.