Skip to content

Tailwind CSS - Overscroll Behavior

Tailwind’s Overscroll Behavior utilities give you control over what happens when a user scrolls past the boundary of a container. This is crucial for preventing “scroll chaining,” where scrolling an element (like a modal or sidebar) also scrolls the content behind it.

These classes allow you to define the browser’s scrolling behavior at both the element and page level.

ClassCSS Properties
overscroll-autooverscroll-behavior: auto;
overscroll-containoverscroll-behavior: contain;
overscroll-noneoverscroll-behavior: none;
overscroll-y-containoverscroll-behavior-y: contain;
overscroll-y-noneoverscroll-behavior-y: none;
overscroll-x-containoverscroll-behavior-x: contain;
overscroll-x-noneoverscroll-behavior-x: none;
  • overscroll-auto (Default): Normal scrolling. When you hit the end of an element, the parent container (including the main page) will begin to scroll.
  • overscroll-contain: The most common use case. It prevents scroll chaining. Scrolling is “contained” within the element. The parent will not scroll. However, it still allows the browser’s native overscroll effects, like the “bounce” on macOS/iOS.
  • overscroll-none: The strictest option. It prevents scroll chaining AND disables the browser’s native overscroll effects. This can be useful but may feel unnatural to some users.

Let’s build a modal with long content. Without overscroll control, scrolling to the bottom of the modal would cause the page behind it to scroll. We’ll use overscroll-contain to fix this.

Note: To make this example fully interactive, you would use JavaScript to toggle the visibility of the modal.

<!-- The main page with lots of content to demonstrate scrolling -->
<body class="bg-slate-200 h-[200vh]">
<div class="p-8">
<h1 class="text-3xl font-bold">Scroll down to see the issue...</h1>
</div>
<!-- The Modal Overlay -->
<!-- In a real app, you'd add/remove a class like 'hidden' with JS -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4">
<!-- The Modal Panel -->
<div class="bg-white rounded-lg shadow-xl max-w-lg w-full">
<div class="p-4 border-b">
<h2 class="text-xl font-semibold">Modal Title</h2>
</div>
<!-- The Scrollable Content Area -->
<!-- Apply `overscroll-contain` here to prevent background scroll -->
<div class="p-4 h-64 overflow-y-auto overscroll-contain">
<p class="text-slate-700 mb-4">This is the scrollable content area of the modal. Try scrolling to the top or bottom.</p>
<div class="h-[500px] bg-gradient-to-b from-cyan-200 to-blue-200 rounded flex items-center justify-center">
<p class="font-mono">Tall Content</p>
</div>
<p class="text-slate-700 mt-4">Without `overscroll-contain`, the page behind this modal would start scrolling once you hit the end. With it, the scroll is trapped inside this element.</p>
</div>
<div class="p-4 border-t flex justify-end">
<button class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">Close</button>
</div>
</div>
</div>
</body>

A common UX pattern is to completely prevent the <body> from scrolling when a modal is open. You can achieve this by adding an overflow-hidden or overscroll-none class to the <body> element via JavaScript when the modal becomes visible, and removing it when the modal is closed.

You can use axis-specific utilities like overscroll-x-contain for horizontally scrolling carousels. This ensures that a user’s horizontal swipe doesn’t accidentally trigger a vertical scroll on the page, providing a much smoother user experience.

<div class="flex space-x-4 overflow-x-auto p-4 bg-white overscroll-x-contain snap-x snap-mandatory">
<!-- Carousel items -->
<div class="snap-start shrink-0 w-64 h-32 bg-blue-200 rounded">Item 1</div>
<div class="snap-start shrink-0 w-64 h-32 bg-green-200 rounded">Item 2</div>
<div class="snap-start shrink-0 w-64 h-32 bg-yellow-200 rounded">Item 3</div>
<div class="snap-start shrink-0 w-64 h-32 bg-red-200 rounded">Item 4</div>
</div>