react-spectrum
react-spectrum copied to clipboard
`SSRProvider` creates issues with conditionally-rendered `OverlayContainer`s
🐛 Bug Report
When wrapping an app with SSRProvider, conditionally-rendered overlays don't display correctly on the first display. If you show one based on state.isOpen from a trigger, the rendering is odd the first go. In my app's case, the tooltip that should be rendered stays offscreen until mousing away, then the overlay flashes on and off in a second. Hovering over the same element again, the overlay displays correctly.
I created a sandbox that shows a similar problem. In the sandbox, the overlay shows, but the offset is being ignored.
These issues only show up when the app is wrapped in an SSRProvider. If the provider is removed, the overlays display as expected, but then the app complains about SSR and IDs.
I can side-step the issue by conditionally rendering the content inside the OverlayContainers, but this results in hundreds of portals sitting at the bottom of body.
🤔 Expected Behavior
I expect overlays to display correctly even when the app is wrapped in an SSRProvider.
😯 Current Behavior
Overlays exhibit odd behavior, sometimes not showing at all, or having odd positionProps.style values when wrapped with SSRProvider.
🔦 Context
I'm building a Remix app that would seemingly require SSRProvider and I have lots of menus and tooltips that need to be in OverlayContainers because of overflowing/scrolling parents.
💻 Code Sample
https://codesandbox.io/s/react-spectrum-template-forked-9io4uj?file=/src/index.js
🌍 Your Environment
| Software | Version(s) |
|---|---|
| react-aria | 3.19.0 |
| react-stately | 3.17.0 |
| Chrome | 103 |
| macOS | 12.5.1 |
We have the same problem, and i found this issue which might be related to the problem.
https://github.com/adobe/react-spectrum/issues/3293
Exactly the same issue 🫡
Update: 2022-09-09. After playing around today a bit more, I was able to get an OverlayContainer to conditionally render when triggered off of useMenuTrigger by moving the OverlayContainer inside the Popover component and then conditionally rendering the Popover. Works as expected.
Tried the same with my Tooltip, but no matter what I do, the Tooltip (using OverlayContainer) won't position itself when conditionally rendered and the OverlayContainer is inside the conditionally rendered component. If I conditionally render inside the OverlayContainer, things look fine, but there are a hundred OverlayContainers in the body. Also, if I remove the SSRProvider, everything works as expected, but React Aria yells at me about IDs not matching.
Update: 2022-09-09. After playing around today a bit more, I was able to get an OverlayContainer to conditionally render when triggered off of
useMenuTriggerby moving the OverlayContainer inside the Popover component and then conditionally rendering the Popover. Works as expected.Tried the same with my Tooltip, but no matter what I do, the Tooltip (using OverlayContainer) won't position itself when conditionally rendered and the OverlayContainer is inside the conditionally rendered component. If I conditionally render inside the OverlayContainer, things look fine, but there are a hundred OverlayContainers in the body. Also, if I remove the SSRProvider, everything works as expected, but React Aria yells at me about IDs not matching.
I've made it work by manually handling the ref in a callback, and then calling updatePostion which is returned from the useOverlayPosition hook.
const popoverRefCallback = useCallback(
(ref: HTMLDivElement) => {
popoverRef.current = ref;
updatePosition();
},
[popoverRef, updatePosition]
);
I've made it work by manually handling the ref in a callback, and then calling
updatePostionwhich is returned from theuseOverlayPositionhook.const popoverRefCallback = useCallback( (ref: HTMLDivElement) => { popoverRef.current = ref; updatePosition(); }, [popoverRef, updatePosition] );
@rk-lunar
Ah, that took care of it! Thank you very much for the workaround.
I don't know if the above workaround is the solution to this problem or if it should work without the callbackRef. Will leave this open for now.
Did anyone figure out a workaround when using useMenu? I'm running into the same issue when trying to incorporate the styled example inside a Next.JS project and SSRProvider breaks it 😅
@brandonpittman sorry if I'm missing context but why did you close the issue?
https://github.com/adobe/react-spectrum/issues/3490#issuecomment-1241670866
@eramdam I expect that our workaround should work there as well, but passing the menu trigger state instead of the overlay trigger state.
@brandonpittman I don't think that the existence of a workaround means that the bug is no longer present? Ideally, that (or our) workaround wouldn't be necessary.
@eramdam I expect that our workaround should work there as well, but passing the menu trigger state instead of the overlay trigger state.
@brandonpittman I don't think that the existence of a workaround means that the bug is no longer present? Ideally, that (or our) workaround wouldn't be necessary.
Yep, your work around works!
I've made it work by manually handling the ref in a callback, and then calling
updatePostionwhich is returned from theuseOverlayPositionhook.
I'm using usePopover() which doesn't return an updatePosition() method... how would I work around the issue when using usePopover()?
I don't understand why this issue was closed. This is still a bug... :/
Mine was broken with the examples for useSelect, but this workaround from #3787 fixed it fine:
<Overlay portalContainer={document.body}>
...
</Overlay>
This is in a Remix app where we hydrate the entire <html> element; I think it was getting confused about where to send the portal perhaps?