feat(RAC): expose --page-width and --visual-viewport-width from Modal#9318
feat(RAC): expose --page-width and --visual-viewport-width from Modal#9318snowystinger merged 2 commits intoadobe:mainfrom
--page-width and --visual-viewport-width from Modal#9318Conversation
--page-width and --visual-viewport-width from M…--page-width and --visual-viewport-width from Modal
09625c8 to
677c5c5
Compare
|
@devongovett Hi, any chance to get this merged before next release? This is necessary for our project. |
|
@lixiaoyan I'll ask the team, but just to set realistic expectations, it's unlikely to be added this release. We're just a little too late in the cycle with our main priorities on S2 going to 1.0 and our new docs site. I think I can say we would all think this is fairly low risk because it matches the equivalent for height, but it would still need to be discussed and tested. You can use it with a yarn patch or something equivalent in the meantime. Thank you for understanding. |
|
I brought it up, the team judged it was just too close to release to take this in. In addition, we were curious if you had tried using |
I only see the scrollbars the first time I close a Modal, after that it's fine. Given that it has 100vw both times, it doesn't seem like that is the culprit? |
Hm, for me it happens always. The new docs page doesn't have a vertical scrollbar but after closing the dialog a vertical scrollbar appears and stays there, and a horizontal scrollbar appears during the animation. The old docs page already had a vertical scrollbar, the issue there was just a temporary horizontal scrollbar during the animation. Adobe Spectrum does have this problem (and doesn't use 100vw). modal-scrollbar.mp4 |
|
Odd, now I'm incapable of reproducing in Chrome or Safari or Firefox. Neither Modal or Dialog docs pages in either library |
|
If you are on macOS, did you enable "Show scrollbar: always" in the OS settings? My screenshot is from macOS with this setting enabled, the video is from Windows (which always shows scrollbars, not just on scroll). |
|
Anyhow, the |
Sorry, I should have specified, I always have scrollbars on. I dislike hiding them :)
But what do you need it for? Can you provide an example which demonstrates what you'd use it for? I know there's a bit of an example in the description, but I unfortunately may make different assumptions about setup. |
|
Oh, just found out it's caused by the 1Password browser extension, so nothing you have to worry about. I should have tested this in a clean browser profile 😕 (And my comment above is wrong, I meant it does not happen in Adobe Spectrum, that's why assume it's somehow related to the 100vw). Sorry for the interruption here. |
|
I'm really sorry, but I'm not understanding those pictures. Would you mind taking our Tailwind Starter https://react-aria.adobe.com/getting-started#storybook-starter-kits and modifying that to show the problem then pushing it to Github and sharing it here? That way we can run it and it'll be as close to your setup as possible. Otherwise, I need some really thorough instructions on how to get to those images. Some things to keep in mind. It's worth noting that the reason for page-height and viewport-height variables was specifically due to iOS nav bars, which only affect height. |
|
@snowystinger https://github.com/lixiaoyan/rac-modal-horizontal-scroll Screen.Recording.2025-12-19.at.9.46.37.PM.mov
However, there is one remaining issue with the new approach offered in this PR: the scrollbar gutter clips the drawer's right side. It's related to a CSS spec issue: w3c/csswg-drafts#8099. Chrome includes the scrollbar gutter's width in the visual viewport width, while Firefox and Safari do not. #9199 has the same root cause. As I suggested in #9199 (comment), we may need a new util to calculate the visual viewport size without the scorllbar. const width = Math.min(visualViewport.width, document.documentElement.clientWidth);
const height = visualViewport.height;Edited: |
The To quickly reproduce, goto https://react-spectrum.adobe.com/Dialog and set the |
|
After some investigations, I discovered that, regardless of iOS, even when using
^ Screenshot of https://jsbin.com/vefumujapa/1/edit?html,css,js,output with an older version Chrome |
5c2dfb6 to
094ac82
Compare
|
|
||
| let visualViewport = typeof document !== 'undefined' && window.visualViewport; | ||
|
|
||
| export function useViewportSize(): ViewportSize { |
There was a problem hiding this comment.
We might rename this useVisualViewportSize because it returns the visual viewport size (does not include the scrollbar) but not the 100vw one.
|
@devongovett WDYT? |
|
Tested with https://interop-2022-viewport.netlify.app/
|
| // The visual viewport width may include the scrollbar gutter. We should use the minimum width between | ||
| // the visual viewport and the document element to ensure that the scrollbar width is always excluded. | ||
| // See: https://github.com/w3c/csswg-drafts/issues/8099 | ||
| ? Math.min(visualViewport.width * visualViewport.scale, document.documentElement.clientWidth) |
There was a problem hiding this comment.
Unfortunately, this line still cannot get the correct ICB width. We may need to insert an empty <div> with position: absolute; width: 100% inside <body> and use its clientWidth for the ICB width. document.documentElement.getBoundingClientRect().width may also work, as long as no width style applied to the <html>.
There was a problem hiding this comment.
based on your other comment, this was fixed in Chrome 136? Or was that a different issue? Do we still need this?
|
Another option is to use something like <ModalOverlay className="absolute top-0 left-(--page-scroll-left) h-(--page-height) w-full">
<Modal className="grid justify-items-end sticky top-0 h-(--visual-viewport-height) w-full">
<Dialog />
</Modal>
</ModalOverlay>Edited: I filled a new PR with the method described above. #9383 |
devongovett
left a comment
There was a problem hiding this comment.
I think we're ok with this. Just one question above on the change to useViewportSize.
snowystinger
left a comment
There was a problem hiding this comment.
comment can be answered and we can follow it up
|
Unfortunately, the latest version of Chrome still has issues, meaning the changes made to The fix introduced in Chrome 136 only addresses the positioning of Consequently, even with this PR in its current state, content will still be obscured by the scrollbar in the latest version of Chrome (v146). Currently, there is no reliable DOM API to accurately get the viewport width excluding the scrollbar in Chrome. I can think of two viable approaches moving forward:
|
|
Calling Additionally, this |
|
@lixiaoyan A bit hacky, but how about calculating the visual viewport ourselves like this: let style = getComputedStyle(document.documentElement);
let scrollBarStyle = style.scrollbarWidth;
let scrollWidth = document.documentElement.scrollWidth;
document.documentElement.style.scrollbarWidth = 'none';
let scrollBarWidth = document.documentElement.scrollWidth - scrollWidth;
document.documentElement.style.scrollbarWidth = scrollBarStyle;
let visualViewportWidth = window.innerWidth - scrollBarWidth;Seems to work in all browsers pretty consistently and avoids this large mess of a polyfill. To make this even more reliable, while also avoiding potential flicker, we could also copy style from the documentElement onto a hidden element, then measure the scrollbar there - similar to our |
|
@lixiaoyan Yes, I understand what the issue is about. Thanks for filing it btw.
What I don't understand is why we can't use |
|
@nwidynski We can, but we still have no reliable way to determine the scrollbar gutter width either. From the library's perspective, the user may override the scrollbar style on the |










This allows us to properly place a dialog in a horizontally scrolled page (
document.scrollingElement.scrollLeft !== 0).✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: