Search code examples
reactjsmenudropdown

@radix-ui/react-dropdown-menu content is displayed incorrectly


I am using @radix-ui/react-dropdown-menu with my Button component inside the Trigger (with asChild prop) and the dropdown content is displayed incorrectly (if I replace Button with the html button, the content is displayed normally).

For some reason the dropdown content css is like this transform: translate3d(0px, -200%, 0px) when I am using my Button component, but when I used the html button everything works fine

import * as React from "react";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";

const Button = (props) => {
  return <button {...props} />;
};

export function App() {
  return (
    <div className="App">
      <div>
        <DropdownMenu.Root>
          <DropdownMenu.Trigger asChild>
            <Button type="button">test 1</Button>
            {/* <button type="button">test 2</button> */}
          </DropdownMenu.Trigger>

          <DropdownMenu.Content>
            <DropdownMenu.Item>menu item</DropdownMenu.Item>
            <DropdownMenu.Item>menu item</DropdownMenu.Item>
            <DropdownMenu.Item>menu item</DropdownMenu.Item>
          </DropdownMenu.Content>
        </DropdownMenu.Root>
      </div>
    </div>
  );
}

Solution

  • Radix requires you to add a forwardRef to components when you want to use asChild.

    In your case:

    const Button = React.forwardRef((props, forwardedRef) => (
      <button {...props} ref={forwardedRef} />
    ));
    

    https://www.radix-ui.com/primitives/docs/guides/composition#your-component-must-forward-ref

    Additionally, Radix will sometimes need to attach a ref to your component (for example to measure its size). If your component doesn't accept a ref, then it will break.

    Whilst this isn't necessary for all parts, we recommend always doing it so that you are not concerned with implementation details. This is also generally good practice anyway for leaf components.