I added my auth buttons into a material menu on my site, and it's proving to be a pain. I have the menu anchored to the right, so it aligns with the bottom right of my Login button and expands to the left. However, the Google button resizes itself in an iframe after a login attempt on the app, and since the material menu anchors with the left position, it resizes to the right.
I tried aligning the button to the right of the li
, but this does not prevent the menu from resizing to the right because it is always absolutely positioned with top
and left
no matter what your anchor configuration is.
I have also tried using a style override on the component. Setting right
css styling partially works, but material insists on setting left
regardless of whether I try to override null
or undefined
, so it doesn't allow the menu to resize vertically.
I am attempting to use a ref to the menu paper scroll width to set left
, but the ref is null
on a useEffect
with respect to isMenuOpen
, so I'll have to dig into that more.
<Menu
id='login-menu'
ref={menuRef}
disableAutoFocusItem
disableScrollLock={true}
anchorEl={menuAnchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={isMenuOpen}
onClose={() => setMenuAnchorEl(undefined)}
MenuListProps={{
'aria-labelledby': 'login-button',
style: { padding: 0 },
}}
slotProps={{
root: {
style: { display: 'contents' },
},
paper: {
ref: menuPaperRef,
style: {
left:
(menuAnchorEl?.getBoundingClientRect().right ??
window.innerWidth) - (menuPaperRef.current?.scrollWidth ?? 0),
right:
window.innerWidth -
(menuAnchorEl?.getBoundingClientRect().right ?? 0),
},
},
}}
>
Example of the issue (the right edge of the menu should align with the right edge of the Login button):
I added my auth buttons into a material menu on my site, and it's proving to be a pain. I have the menu anchored to the right, so it aligns with the bottom right of my Login button and expands to the left. However, the Google button resizes itself in an iframe after a login attempt on the app, and since the material menu anchors with the left position, it resizes to the right.
I tried aligning the button to the right of the li
, but this does not prevent the menu from resizing to the right because it is always absolutely positioned with top
and left
no matter what your anchor configuration is.
I have also tried using a style override on the component. Setting right
css styling partially works, but material insists on setting left
regardless of whether I try to override null
or undefined
, so it doesn't allow the menu to resize vertically.
I am attempting to use a ref to the menu paper scroll width to set left
, but the ref is null
on a useEffect
with respect to isMenuOpen
, so I'll have to dig into that more.
<Menu
id='login-menu'
ref={menuRef}
disableAutoFocusItem
disableScrollLock={true}
anchorEl={menuAnchorEl}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={isMenuOpen}
onClose={() => setMenuAnchorEl(undefined)}
MenuListProps={{
'aria-labelledby': 'login-button',
style: { padding: 0 },
}}
slotProps={{
root: {
style: { display: 'contents' },
},
paper: {
ref: menuPaperRef,
style: {
left:
(menuAnchorEl?.getBoundingClientRect().right ??
window.innerWidth) - (menuPaperRef.current?.scrollWidth ?? 0),
right:
window.innerWidth -
(menuAnchorEl?.getBoundingClientRect().right ?? 0),
},
},
}}
>
Example of the issue (the right edge of the menu should align with the right edge of the Login button):
I want to share a somewhat hacky workaround - using a ResizeObserver
on the problem button, I was able to effectively force the left position based on the right and the resulting width (reference).
I want to stress that this solution is very inconsistent and less performant than simply using right
instead of left
, so if there is a way to do so, I'm still on the lookout for answers.
I'm not sure I understand your problem but you can use this utility function to get position of a ref and then apply an offset.
type Align = 'left' | 'right';
interface CalculatePositionParams {
ref: HTMLElement;
align?: Align;
verticalOffset?: number;
horizontalOffset?: number;
}
const getPosition = (params: CalculatePositionParams): PositionResult => {
const { ref, align = 'left', verticalOffset = 0, horizontalOffset = 0 } = params;
const rect = ref.getBoundingClientRect();
let top = rect.bottom + verticalOffset + window.scrollY;
let left: number | undefined;
let right: number | undefined;
if (align === 'left') {
left = rect.left + horizontalOffset;
} else if (align === 'right') {
right = window.innerWidth - rect.right + horizontalOffset;
}
return { top, left, right };
};
This will return an object that you can use on an html element as a style.