primitives icon indicating copy to clipboard operation
primitives copied to clipboard

Triggering Dialog raise error when using nested component from React.Children

Open marckraw opened this issue 3 years ago • 1 comments
trafficstars

Bug report

Current Behavior

I'm building Modal component, using Dialog primitive from radix-ui. Everything worked amazing until i decided that our Modal component will use React.Children to map nested component to proper places inside Dialog.Root wrapper.

The problem is, that there is an error showing app in console when triggering modal/dialog (everything on frontend seems to work as expected but.. well error is happening :)

image

Here is the repository where there is example of what i'm talking about:

  • https://github.com/marckraw/slot-issue-radix
Here is deployed version of it to see the issue instantly: - https://slot-issue-radix.vercel.app/

(While writing this issue, found out that it doesnt happen after deployed to production version of Next.js, but is happening locally)

Here is the main part of component

const Modal: FC<ModalProps> = ({ children }) => {
  const childrenArray = React.Children.toArray(children);
  console.log(childrenArray);
  const toSlots = childrenArray.reduce((prev: any, next: any) => {
    return {
      ...prev,
      [next.type.displayName]: next,
    };
  }, {});

  console.log(toSlots);
  return (
    <Dialog.Root>
      {toSlots.ModalTrigger}
      <Dialog.Portal>
        <Dialog.Overlay className={styles.modalOverlay} />
        {toSlots.ModalContent}
      </Dialog.Portal>
    </Dialog.Root>
  );
};

And part where we use this component:

<Modal>
  <ModalTrigger>Trigger my modal</ModalTrigger>
  <ModalContent>
    <h2 style={{ marginTop: 0 }}>Demo</h2>
    <p>
      Pellentesque habitant morbi tristique senectus et netus et malesuada
      fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae,
      ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam
      egestas semper. Aenean ultricies mi vitae est. Mauris placerat
      eleifend leo.
    </p>
    <p>
      Pellentesque habitant morbi tristique senectus et netus et malesuada
      fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae,
      ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam
      egestas semper. Aenean ultricies mi vitae est. Mauris placerat
      eleifend leo.
    </p>
  </ModalContent>
</Modal>

Expected behavior

Should not raise an error.

Reproducible example

https://github.com/marckraw/slot-issue-radix

Your environment

React, Next.js, newest Radix Dialog component

marckraw avatar Aug 09 '22 10:08 marckraw

@marckraw Seems this approach is attempting to pass refs to your standard function comps, the message wouldn't appear in prod as it's a dev only warning afaik.

One solution would be to simply ensure all of you recomposition's forward a ref correctly, eg:

const ModalContent = React.forwardRef(({ children, ...rest }, forwardedRef) => {
  return (
    <Dialog.Content {...rest} className={styles.modalContent} ref={forwardedRef}>
      {children}
      <Dialog.Close>Exit</Dialog.Close>
    </Dialog.Content>
  );
});

Though I'm curious on this approach, why not simply close over the Portal and Overlay inside ModalContent?

andy-hook avatar Aug 10 '22 10:08 andy-hook

@andy-hook ah yeah, now it works perfectly fine in dev and prod, when passing refs :)

Thx!

marckraw avatar Aug 12 '22 10:08 marckraw