How to Fix Page Scrolling When Using a Scrollable Shadcn/ui Popover
A common issue when building with Shadcn/ui is placing scrollable content inside a PopoverContent
component. When a user tries to scroll this content, the entire page often scrolls instead, creating a frustrating user experience.
The Problem: Event Bubbling
This happens because of a browser feature called event bubbling. The scroll event (like wheel
for a mouse or touchmove
for a touch screen) doesn't stop at your scrollable element. It "bubbles up" the DOM tree until it reaches the main page's <body>
or <html>
element, which then handles the event by scrolling the entire window.
Problematic Code:
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
<Popover>
<PopoverTrigger>Open</PopoverTrigger>
<PopoverContent>
{/* This div won't scroll correctly; the page will scroll instead. */}
<div className="h-48 overflow-y-auto">
<p>Lots of content here...</p>
<p>...that needs to scroll...</p>
</div>
</PopoverContent>
</Popover>
The Solution: event.stopPropagation()
The fix is to intercept the scroll event at the PopoverContent
level and stop it from bubbling any further up the DOM. You can do this by adding event handlers to the onWheel
and onTouchMove
props and calling event.stopPropagation()
.
Solution Code:
import { Popover, PopoverTrigger, PopoverContent } from '@/components/ui/popover';
// A simple handler to stop event propagation
const stopPropagation = (e) => e.stopPropagation();
<Popover>
<PopoverTrigger>Open</PopoverTrigger>
{/* Attach the handlers to stop wheel and touch events from bubbling */}
<PopoverContent
onWheel={stopPropagation}
onTouchMove={stopPropagation}
>
{/* This div will now scroll correctly without affecting the page. */}
<div className="h-48 overflow-y-auto">
<p>Lots of content here...</p>
<p>...that needs to scroll...</p>
</div>
</PopoverContent>
</Popover>
By adding these two props, you ensure that scroll actions within the popover are contained, providing the smooth, expected behavior for your users.