Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(site): stop forcing overflow-y on the scroll-locked body
The global scrollbar rules forced overflow-y: scroll on
body[data-scroll-locked] so the scrollbar would not disappear while a
Radix overlay was open. On the agents page, where <html> has inline
overflow: hidden, the forced scroll no longer propagated to the
viewport and instead grew a scrollbar on <body>, reserving width and
shrinking the page every time a popover opened.

The forced scroll is unnecessary: scrollbar-gutter: stable keeps the
gutter reserved while the body is locked, so page width is stable even
though the scrollbar is hidden. Remove it, along with the agents page
<style> injection that existed only to override it.
  • Loading branch information
DanielleMaywood committed Sep 11, 2026
commit 2c40abcb18e371b80c82d15077645dca2bf7f554
10 changes: 9 additions & 1 deletion site/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,15 @@
over Radix's injected !important styles. The @supports guard ensures
we only do this on browsers that actually support scrollbar-gutter.

The reserved gutter is kept while the body is scroll-locked, so the
page keeps its width even though Radix hides the body scrollbar. For
this to hold, do not force overflow-y on the locked body: hiding the
scrollbar while the gutter reserves its space is what prevents the
shift, and any forced overflow here would fight react-remove-scroll's
lock styles (its lower-specificity selector must lose or the page
gains a scrollbar on pages where the body owns the overflow, like
/agents).

There’s a related issue on GitHub: Radix UI Primitives Issue #3251
https://github.com/radix-ui/primitives/issues/3251
*/
Expand All @@ -762,7 +771,6 @@
html body[data-scroll-locked] {
--removed-body-scroll-bar-size: 0 !important;
margin-right: 0 !important;
overflow-y: scroll !important;
}
}

Expand Down
23 changes: 4 additions & 19 deletions site/src/pages/AgentsPage/AgentsPageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,19 +184,10 @@ const AgentsPageLayout: FC = () => {
// uses its own internal scroll containers so the reserved gutter
// space is unnecessary and wastes horizontal room.
//
// Removing the gutter requires three things:
//
// 1. overflow:hidden on both <html> and <body> so neither element
// can produce a scrollbar.
// 2. scrollbar-gutter:auto on <html> so the browser stops
// reserving space for a scrollbar that will never appear.
// This is what makes react-remove-scroll-bar measure a gap of
// 0 when a Radix dropdown opens, so it injects no padding or
// margin compensation.
// 3. An injected <style> that overrides the global
// `overflow-y: scroll !important` on body[data-scroll-locked].
// Without this, opening any Radix dropdown would force a
// scrollbar onto <body>, re-introducing the layout shift.
// Removing the gutter requires overflow:hidden on both <html> and
// <body> so neither element can produce a scrollbar, plus
// scrollbar-gutter:auto on <html> so the browser stops reserving
// space for a scrollbar that will never appear.
useEffect(() => {
const html = document.documentElement;
const body = document.body;
Expand All @@ -209,16 +200,10 @@ const AgentsPageLayout: FC = () => {
html.style.scrollbarGutter = "auto";
body.style.overflow = "hidden";

const style = document.createElement("style");
style.textContent =
"html body[data-scroll-locked] { overflow-y: hidden !important; }";
document.head.appendChild(style);

return () => {
html.style.overflow = prevHtmlOverflow;
html.style.scrollbarGutter = prevHtmlScrollbarGutter;
body.style.overflow = prevBodyOverflow;
style.remove();
};
}, []);

Expand Down
Loading