ui
ui copied to clipboard
Position of NavigationMenuViewport
When we need a more extensive Navigation Menu, Viewport with Content does not follow the position of the Trigger. Instead, all menus are in the center of the screen. You can see behavior on this test page: https://chakras-edtsr25u2-miljenko-storydeckio.vercel.app/
The same issues are mentioned here: https://github.com/radix-ui/primitives/issues/1462
Is there any parameter to position Viewport under the Trigger point?
I'm also pretty confused about the best way to fix this. I simply want the viewport to show underneath the trigger.
There's a fix here https://github.com/shadcn/ui/pull/102. Does this help?
Fix #102 is ok if you have a few items in the menu bar. In our case, we have six "MenuTrigers" solution #102 is suitable for "MenuTriggers" in the middle of the screen but not ideal for the first and last "MenuTrigger" elements.
We are looking for this type of solution: https://codesandbox.io/s/simple-navigation-menu-em1qrc?file=/src/App.js
Each "MenuContent" drop-down element is strictly under "MenuTrigger."
Anyone got an update to this? I have the same issue
Any resolution, I'm currently facing the same problem.
I also faced this problem, do you have any solutions?
I fixed by removing NavigationMenuViewport
in NavigationMenu
component and using <NavigationMenuContent className="absolute top-full">
instead to display the submenu items.
Hope this will help
A better solution would be to make it as Prop to be able to set it dynamically.
I tried @artur-dani answer but didn't work.
I found this answer instead: Add right:0 absolute left-auto top-full w-auto
to <NavigationMenuContent ... />
and completely remove <NavigationMenuViewport />
from <NavigationMenu />
I don't know if it will break something, but is working at least
I tried @artur-dani answer but didn't work.
I found this answer instead: Add
right:0 absolute left-auto top-full w-auto
to<NavigationMenuContent ... />
and completely remove<NavigationMenuViewport />
from<NavigationMenu />
I don't know if it will break something, but is working at least
This work but it will disable the closing of the submenu when clicked outside.
What I did is to add submenu-trigger
class to all NavigationMenuTrigger
and submenu-viewport
class to NavigationMenuViewport
and use the following script to update the left position of the viewport using the @update:model-value
on NavigationMenu
.
function onNavChange() {
setTimeout(() => {
const triggers = document.querySelectorAll('.submenu-trigger[data-state="open"]')
if (triggers.length === 0)
return
const firstTrigger = triggers[0] as HTMLElement
const viewports = document.getElementsByClassName('submenu-viewport')
if (viewports.length > 0) {
const viewport = viewports[0] as HTMLElement
viewport.style.left = `${firstTrigger.offsetLeft}px`
}
})
}
<NavigationMenu @update:model-value="onNavChange">
<NavigationMenuViewport class="submenu-viewport">
<NavigationMenuTrigger class="submenu-trigger">
I tried @artur-dani answer but didn't work. I found this answer instead: Add
right:0 absolute left-auto top-full w-auto
to<NavigationMenuContent ... />
and completely remove<NavigationMenuViewport />
from<NavigationMenu />
I don't know if it will break something, but is working at leastThis work but it will disable the closing of the submenu when clicked outside. What I did is to add
submenu-trigger
class to allNavigationMenuTrigger
andsubmenu-viewport
class toNavigationMenuViewport
and use the following script to update the left position of the viewport using the@update:model-value
onNavigationMenu
.function onNavChange() { setTimeout(() => { const triggers = document.querySelectorAll('.submenu-trigger[data-state="open"]') if (triggers.length === 0) return const firstTrigger = triggers[0] as HTMLElement const viewports = document.getElementsByClassName('submenu-viewport') if (viewports.length > 0) { const viewport = viewports[0] as HTMLElement viewport.style.left = `${firstTrigger.offsetLeft}px` } }) } <NavigationMenu @update:model-value="onNavChange"> <NavigationMenuViewport class="submenu-viewport"> <NavigationMenuTrigger class="submenu-trigger">
Could you elaborate on the @update:model-value="onNavChange"
part? trying to use this in nextjs in the NavigationMenu
component is giving me errors.
I just found a solution for me
I just create a component for NavigationMenuItem and add 'relative' to it.
const NavigationMenuItem = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Item>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Item
ref={ref}
className={cn("relative", className)}
{...props}
/>
));
NavigationMenuItem.displayName = 'NavigationMenuItem';
BTW I remove Navigation MenuViewport too and add this to the Menu
const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"right-0 absolute",
"absolute top-full w-fit bg-popover mt-[5px]",
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52",
className
)}
{...props}
/>
));
Hope it helps.
Example Image:
I just found a solution for me
I just create a component for NavigationMenuItem and add 'relative' to it.
const NavigationMenuItem = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Item>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Item> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Item ref={ref} className={cn("relative", className)} {...props} /> )); NavigationMenuItem.displayName = 'NavigationMenuItem';
BTW I remove Navigation MenuViewport too and add this to the Menu
const NavigationMenuContent = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Content>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Content ref={ref} className={cn( "right-0 absolute", "absolute top-full w-fit bg-popover mt-[5px]", "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52", className )} {...props} /> ));
Hope it helps.
Example Image:
thanks that works for me perfectly.
I just found a solution for me
I just create a component for NavigationMenuItem and add 'relative' to it.
const NavigationMenuItem = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Item>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Item> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Item ref={ref} className={cn("relative", className)} {...props} /> )); NavigationMenuItem.displayName = 'NavigationMenuItem';
BTW I remove Navigation MenuViewport too and add this to the Menu
const NavigationMenuContent = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Content>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Content ref={ref} className={cn( "right-0 absolute", "absolute top-full w-fit bg-popover mt-[5px]", "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52", className )} {...props} /> ));
Hope it helps.
Example Image:
A full year and this is such a gem to find... Thank you, it still works which means the problem was never looked into after this issue opened.
I removed the reference to NavigationMenuViewport
in NavigationMenu
in the navigation-menu.ts
file.
const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className
)}
{...props}
>
{children}
{/* <NavigationMenuViewport /> */}
</NavigationMenuPrimitive.Root>
))
I modified NavigationMenuContent to the following because the previous example left out the styling of the default MenuViewport which includes a border and shadow.
const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 absolute",
"absolute top-full w-fit bg-popover mt-[5px]",
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52",
"origin-top-center absolute mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className
)}
{...props}
/>
))
Here is the result:
I removed the reference to
NavigationMenuViewport
inNavigationMenu
in thenavigation-menu.ts
file.
Yep, also just found that solution
Finally found a solution here. Thanks for this thread, I've been trying to fix this for hours
The default behavior is so broken, both implementations from @dongnez and @AoverK are way better, thanks for sharing 💜
I just found a solution for me
I just create a component for NavigationMenuItem and add 'relative' to it.
const NavigationMenuItem = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Item>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Item> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Item ref={ref} className={cn("relative", className)} {...props} /> )); NavigationMenuItem.displayName = 'NavigationMenuItem';
BTW I remove Navigation MenuViewport too and add this to the Menu
const NavigationMenuContent = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Content>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Content ref={ref} className={cn( "right-0 absolute", "absolute top-full w-fit bg-popover mt-[5px]", "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52", className )} {...props} /> ));
Hope it helps.
Example Image:
thanks worked for me
I removed the reference to
NavigationMenuViewport
inNavigationMenu
in thenavigation-menu.ts
file.const NavigationMenu = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Root>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root> >(({ className, children, ...props }, ref) => ( <NavigationMenuPrimitive.Root ref={ref} className={cn( "relative z-10 flex max-w-max flex-1 items-center justify-center", className )} {...props} > {children} {/* <NavigationMenuViewport /> */} </NavigationMenuPrimitive.Root> ))
I modified NavigationMenuContent to the following because the previous example left out the styling of the default MenuViewport which includes a border and shadow.
const NavigationMenuContent = React.forwardRef< React.ElementRef<typeof NavigationMenuPrimitive.Content>, React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content> >(({ className, ...props }, ref) => ( <NavigationMenuPrimitive.Content ref={ref} className={cn( "left-0 absolute", "absolute top-full w-fit bg-popover mt-[5px]", "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52", "origin-top-center absolute mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]", className )} {...props} /> ))
Here is the result:
Thank you!!!! This problem was driving me crazy!
This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.
This is still an issue.
This is still an issue.
Came here to say this is still an issue. Thanks to @AoverK and @dongnez for your fixes!