Dropdowns Inside Scrollable Containers: Why They Break And How To Fix Them Properly

Dropdowns Inside Scrollable Containers: Why They Break And How To Fix Them Properly

Dropdowns Inside Scrollable Containers: Why They Break And How To Fix Them Properly

Dropdowns often work perfectly until they’re placed inside a scrollable panel, where they can get clipped, and half the menu disappears behind the container’s edge. In this article, we will explore why this happens and offer practical solutions to fix it.

The Three Things Actually Causing This

There are three browser systems involved in this issue: overflow clipping, stacking contexts, and containing blocks. Let’s look at each of these items in detail.

The Overflow Problem

When you set overflow: hidden, overflow: scroll, or overflow: auto on an element, the browser will clip anything that extends beyond its bounds, including absolutely positioned descendants.

This means an absolutely positioned menu can be cut off by any ancestor that has a non-visible overflow value, even if that ancestor isn’t the menu’s containing block. Clipping and positioning are separate systems. They just happen to collide in ways that look completely random until you understand both.

See the Pen Overflow & Clipping [forked] by BboyGT.

The Stacking Context Trap

Think of a stacking context as a sealed layer. Whatever is inside it is painted together, as one block. Nothing inside it can escape above something outside it, no matter what z-index you use.

A lot of CSS properties create a new stacking context. I didn’t know half of these triggered a new context until I started debugging z-index issues and had to look them up.

This is exactly why z-index: 9999 sometimes does nothing. If your dropdown is trapped inside a stacking context that paints below another stacking context, its z-index value doesn’t matter at all.

z-index is only compared between siblings in the same stacking context. That’s how a modal with z-index: 1 can sit on top of your dropdown with z-index: 9999. They are not in the same context. The comparison never happens.

That kind of z-index war is never going to be won. You’re fighting in the wrong arena.

See the Pen Stacking Contexts [forked] by BboyGT.

The Containing Block Surprise

Absolute positioning does not mean “position anywhere.” The browser finds the nearest positioned ancestor and treats it as the reference frame for that element’s coordinates and dimensions.

If that ancestor is deep inside a scroll container, the dropdown’s coordinates are calculated relative to it. When the container scrolls, those coordinates don’t update. The trigger moves. The dropdown stays put.

The Fixes That Actually Work

Portals: The Fix That Ultimately Worked For Me

What finally worked for me was getting the dropdown out of the problematic part of the DOM entirely, rendering it directly as a child of document.body instead. In React and Vue, this is called a portal. In vanilla JavaScript, it’s just document.body.appendChild().

Once it’s at the body level, none of the ancestor clipping or stacking context problems apply. The dropdown is outside all of it. z-index works the way you expect it to.

Portalling moves the dropdown out of the ancestor tree entirely. The overflow and stacking context problems don’t follow it because it’s no longer a descendant of either ancestor.

Here’s a React example using createPortal:


import { createPortal } from 'react-dom';

import { useState, useEffect } from 'react';

const App = () => {

const [open, setOpen] = useState(false);

const handleToggle = () => setOpen(!open);

return (

{open && createPortal(
  • Item 1
  • Item 2
, document.body )}
); };

This is a basic example of how you can use portals to fix the issue of dropdowns getting clipped inside scrollable containers.

By moving the dropdown out of the problematic part of the DOM, you can avoid the issues caused by overflow clipping, stacking contexts, and containing blocks.

This approach is not only a fix but also a best practice for building accessible and maintainable UI components.

Conclusion

Dropdowns inside scrollable containers can be a challenging issue to fix, but by understanding the three browser systems involved – overflow clipping, stacking contexts, and containing blocks – you can identify the root cause of the problem and apply the right fix.

Portals are a powerful tool that can help you avoid these issues and build more accessible and maintainable UI components.

By following the examples and best practices outlined in this article, you can create dropdowns that work perfectly even inside scrollable containers.