Description
🙋 Feature Request
we have a header component with position:fixed
overlaid on the main body content. when a modal, menu, or popover opens, padding is added to the <html>
element to compensate for the removed scrollbar.
however, no padding is added to our fixed position <header>
, so the content inside jumps a number of px equal to the size of the scrollbar. this means that menu triggers in the header move around, so they become much harder to toggle!
it would be great to have a way to know that scrolling has been locked, so that we could apply custom styles to any elements that need it besides the body.
🤔 Expected Behavior
make the state of usePreventScroll
consumable from outside the context of the components that call the hook
😯 Current Behavior
there's no way to know whether scroll is being prevented. it's applied via inline styles onto the html
element, and the state is stored in a locally scoped variable preventScrollCount
💁 Possible Solution
there are many ways to solve for this:
- apply a
data-scroll-prevented
attribute to thehtml
element when locking scroll. this would allow using css selectors, event listeners, or observers to subscribe to the state. - apply a custom
class
to thehtml
element. - expose a
useIsScrollPrevented
hook that allows subscribing to state in js-land. this would probably mean changingpreventScrollCount
to some kind of basic observable value / EventTarget, since it would be undesirable to useReact.Context
. I don't see an existing global state management solution inreact-aria
, but anything would work.
happy to help ship a feature if we can decide on the best path forward!
🔦 Context
💻 Examples
examples implementing the three suggestions above, respectively:
const Header = () => (
<>
<header className="site-header">{...}</header>
<style>`
html[data-scroll-prevented=true] header.site-header {
marginRight: ${window.innerWidth - document.documentElement.clientWidth};
}
`
</style>
</>
)
const Header = () => (
<>
<header className="site-header">{...}</header>
<style>`
html.scroll-prevented header.site-header {
marginRight: ${window.innerWidth - document.documentElement.clientWidth};
}
`
</style>
</>
)
const Header = () => {
const isScrollPrevented = useIsScrollPrevented();
return (<>
<header className={isScrollPrevented ? "site-header scroll-prevented" : "site-header"}>{...}</header>
<style>`
header.site-header.scroll-prevented {
marginRight: ${window.innerWidth - document.documentElement.clientWidth};
}
`
</style>
</>)
}
🧢 Your Company/Team
🎁 Tracking Ticket (optional)
(private: https://linear.app/replit/issue/I2C-125)
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
🩺 To Triage