primereact
primereact copied to clipboard
Menu: Popup menu positioning - appendTo
Describe the bug
Same issue as https://github.com/primefaces/primeng/issues/1054. When Menu property popup is enabled and Menu is in a fixed element (e.g. a header with css position: sticky) menu positioning is haywire.
- When
appendToisselfand user scrolls first, then clicksMenu, theMenuappears as far below the containing element as the user has scrolled. - If
appendTois not set,Menuis attached to documentbody(theappendTodefault), so when the user scrolls theMenuscrolls with the body and loses its position. (expected behavior?)
Reproducer
https://codesandbox.io/s/primereact-test-forked-1dlh7o?file=/src/index.js
PrimeReact version
8.1.1
React version
17.x
Language
TypeScript
Build / Runtime
Create React App (CRA)
Browser(s)
No response
Steps to reproduce the behavior
See codesandbox example and description details for steps to reproduce.
Expected behavior
The menu to appear consistently below the sticky containing element regardless of scroll
I've temporarily hacked a patch where I wrap the button and menu element in a div, set to position: relative and fixed height, set Menu appendTo="self" and then override the Menu positioning thus:
.menu-container {
position: relative;
height: 40px;
}
.p-menu {
top: 0 !important;
left: 0 !important;
margin-top: 40px;
}
Obviously this is a hack, not a long-term solution.
Thanks for posting your hack at least! 😄
No prob! It should be an easy fix, likely JS is measuring offset position of "self" element from document top instead of window. If I have time I'll make a PR, but I'm pretty overwhelmed with work right now so don't hold your breath... 😩
@gnowland as with PrimeNG I think the solution is to appendTo the body.
Here is the top calculated correctly for both self and body.
targetOuterHeight = 42
targetOffset.top = 107.75
windowScrollTop = 1128
targetOuterHeight = 42
targetOffset.top = 101.75
windowScrollTop = 1128
I think its always calculating from the top of the body when it calls DomHandler.absolutePosition(menuRef.current, targetRef.current);.
I think by you adding a container element that is relative and setting top left to 0px you are essentially doing all that work instead of just using body no?
appendTo="self"
Worked like a charm for me. Legend! Thank you :)
@gnowland as with PrimeNG I think the solution is to
appendTothebody.Here is the top calculated correctly for both
selfandbody.targetOuterHeight = 42 targetOffset.top = 107.75 windowScrollTop = 1128 targetOuterHeight = 42 targetOffset.top = 101.75 windowScrollTop = 1128I think its always calculating from the top of the
bodywhen it callsDomHandler.absolutePosition(menuRef.current, targetRef.current);.
I think by you adding a container element that is relative and setting top left to 0px you are essentially doing all that work instead of just using
bodyno?
I still don't think this solves the issue. As @gnowland originally mentioned, the issue is when the menu is attached to an element with fixed position, like a navigation bar which stays at the top of the page.
Here is my basic understanding of how the primereact popups work. When the popup is first rendered, it is given an absolute position. Values for top, left, bottom and right are computed relative to the body so that the popup renders right below the element which fired the toggle event. Let us call this the triggering element.
This works nicely with scrolling: if the menu is toggled open and the user scrolls down the page, then the menu and its triggering element will "scroll off" together.
However, there are issues when the triggering element is inside of a fixed element, e.g. a navigation bar which stays at the top of a page. In this case, when the user scrolls down the page, the menu (positioned absolutely, relative to the body) will "scroll off" even while the triggering element stays fixed, thereby causing the menu to be separated from its triggering element.
You might then suggest setting appendTo = 'self' instead of the default appendTo = document.body. However, this still does not work properly, because the absolute position of the popup is always computed relative to body, even when we would like for it to be computed relative to the fixed navigation bar. You will notice the issue when you scroll down the page a bit, and then open the menu via the triggering element in the navigation bar. The popup will appear as far below the navigation bar as you have scrolled.
I would therefore recommend that this issue be reopened.