Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NavigationMenu] Scope Propagation Failure in Custom Components Extending NavigationMenu #2775

Open
daeseong9388 opened this issue Mar 14, 2024 · 0 comments

Comments

@daeseong9388
Copy link

daeseong9388 commented Mar 14, 2024

Bug report

Current Behavior

<CustomNavigationMenu.Root>

  <NavigationMenu.Root>
    <NavigationMenu.Trigger />
    <NavigationMenu.Content>
      <CustomNavigationMenu.Trigger /> 
    </NavigationMenu.Content>
  </NavigationMenu.Root>

  <CustomNavigationMenu.Content />
</CustomNavigationMenu.Root>
const [NavigationMenuItemProviderImpl, useNavigationMenuItemProvider] =
  createContext<NavigationMenuItemContextValue>(ITEM_NAME)

const useNavigationMenuScope = createNavigationMenuScope()

const CustomRoot = React.forwardRef<
  React.ElementRef<typeof NavigationMenuPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => {
  const navigationMenuScope = useNavigationMenuScope(undefined)
  const [value, setValue] = React.useState<string>("")
  return (
    <NavigationMenuProviderImpl value={value} onValueChange={setValue}>
      <NavigationMenuPrimitive.Root
        {...navigationMenuScope}
        ref={ref}
        className={cn(
          "relative z-10 flex max-w-max shrink-0 items-center justify-center",
          className
        )}
        {...props}
      >
        {children}
      </NavigationMenuPrimitive.Root>
    </NavigationMenuProviderImpl>
  )
})
...

image

When extending essential components with scoped contexts, there is an issue where these components, specifically FocusGroup and FocusGroupItem, need to receive and apply their designated scopes properly. This leads to a situation where the FocusGroup and FocusGroupItem might not operate within their intended context boundaries, causing unpredictable and erroneous behaviors.

Expected behavior

When extending components like FocusGroup and FocusGroupItem with scoped contexts, these components should seamlessly inherit and apply their scopes, ensuring they operate strictly within their designated context boundaries.

Reproducible example

https://codesandbox.io/p/sandbox/radix-ui-navigation-memu-bug-report-tx9n7k

Suggested solution

diff --git a/packages/react/navigation-menu/src/NavigationMenu.tsx b/packages/react/navigation-menu/src/NavigationMenu.tsx
index 8ebc0cdd..71c52124 100644
--- a/packages/react/navigation-menu/src/NavigationMenu.tsx
+++ b/packages/react/navigation-menu/src/NavigationMenu.tsx
@@ -373,11 +373,17 @@ const NavigationMenuList = React.forwardRef<NavigationMenuListElement, Navigatio
     const list = (
       <Primitive.ul data-orientation={context.orientation} {...listProps} ref={forwardedRef} />
     );
-
+    const focusGroupProps = { __scopeNavigationMenu };
     return (
       <Primitive.div style={{ position: 'relative' }} ref={context.onIndicatorTrackChange}>
         <Collection.Slot scope={__scopeNavigationMenu}>
-          {context.isRootMenu ? <FocusGroup asChild>{list}</FocusGroup> : list}
+          {context.isRootMenu ? (
+            <FocusGroup {...focusGroupProps} asChild>
+              {list}
+            </FocusGroup>
+          ) : (
+            list
+          )}
         </Collection.Slot>
       </Primitive.div>
     );
@@ -489,10 +495,11 @@ const NavigationMenuTrigger = React.forwardRef<
   const wasClickCloseRef = React.useRef(false);
   const open = itemContext.value === context.value;
 
+  const focusGroupItemProps = { __scopeNavigationMenu };
   return (
     <>
       <Collection.ItemSlot scope={__scopeNavigationMenu} value={itemContext.value}>
-        <FocusGroupItem asChild>
+        <FocusGroupItem {...focusGroupItemProps} asChild>
           <Primitive.button
             id={triggerId}
             disabled={disabled}
@@ -593,9 +600,9 @@ interface NavigationMenuLinkProps extends Omit<PrimitiveLinkProps, 'onSelect'> {
 const NavigationMenuLink = React.forwardRef<NavigationMenuLinkElement, NavigationMenuLinkProps>(
   (props: ScopedProps<NavigationMenuLinkProps>, forwardedRef) => {
     const { __scopeNavigationMenu, active, onSelect, ...linkProps } = props;
-
+    const focusGroupItemProps = { __scopeNavigationMenu };
     return (
-      <FocusGroupItem asChild>
+      <FocusGroupItem {...focusGroupItemProps} asChild>
         <Primitive.a
           data-active={active ? '' : undefined}
           aria-current={active ? 'page' : undefined}
@@ -913,8 +920,9 @@ const NavigationMenuContentImpl = React.forwardRef<
     return attribute;
   }, [context.previousValue, context.value, context.dir, getItems, value]);
 
+  const focusGroupProps = { __scopeNavigationMenu };
   return (
-    <FocusGroup asChild>
+    <FocusGroup {...focusGroupProps} asChild>
       <DismissableLayer
         id={contentId}
         aria-labelledby={triggerId}

Additional context

facebook/react#23287

Your environment

Software Name(s) Version
Radix Package(s) latest
React n/a
Browser Chrome
Assistive tech
Node n/a
npm/yarn yarn
Operating System MAC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant