How to pass props to children?
Answered
Somali posted this in #help-forum
SomaliOP
Good afternoon. I have a question about building what seems like such a thing as a modal in Nex.
Essence:
The project has several modal windows, to implement them I use radix-ui prmitives
My idea is to create a Modal component and inside it pass any content through children, that is, overlay, the close button is the same for all modals.
The component itself looks like this:
The opening and closing logic is implemented by radix itself, but I can also control the opening state through useState.
I also have a Button component
Here the idea is that if there is a prop modalContent (And this is ReactElement), then I create a dialog trigger, which is shown in the Modal composition, inside which the dialog content is thrown through the children
It's used roughly like this.
I need all these wrappers, etc. only because the content in the modal can be a server component in which I need to receive data from the backend.
Perhaps I have complicated the structure too much, but I don’t know what other options there are.
Button - client comp
Modal - client comp
modalContent - server comp
Ideally, I would like the button component, based on some triggers, to be able to open a modal window with any content that I pass to it outside or inside.
The current solution certainly works, but it’s inconvenient, since I can’t call any closeAllMOdals method or close the current modal inside the component. To do this, I need to make the Modal component manageable, but since the Modal content is children, I can’t put open state props into it
I found a solution to how to pass props to children through React.CloneElement, but since I pass the componenet to <Button>, I have an error saying that Children object is not iterable or something like that.
Can you give me some tips for implementation?
Essence:
The project has several modal windows, to implement them I use radix-ui prmitives
My idea is to create a Modal component and inside it pass any content through children, that is, overlay, the close button is the same for all modals.
The component itself looks like this:
The opening and closing logic is implemented by radix itself, but I can also control the opening state through useState.
I also have a Button component
Here the idea is that if there is a prop modalContent (And this is ReactElement), then I create a dialog trigger, which is shown in the Modal composition, inside which the dialog content is thrown through the children
It's used roughly like this.
<Button modalContent={<MainFormServer />}>
Button
</Button>
I need all these wrappers, etc. only because the content in the modal can be a server component in which I need to receive data from the backend.
Perhaps I have complicated the structure too much, but I don’t know what other options there are.
Button - client comp
Modal - client comp
modalContent - server comp
Ideally, I would like the button component, based on some triggers, to be able to open a modal window with any content that I pass to it outside or inside.
The current solution certainly works, but it’s inconvenient, since I can’t call any closeAllMOdals method or close the current modal inside the component. To do this, I need to make the Modal component manageable, but since the Modal content is children, I can’t put open state props into it
I found a solution to how to pass props to children through React.CloneElement, but since I pass the componenet to <Button>, I have an error saying that Children object is not iterable or something like that.
Can you give me some tips for implementation?
Answered by Marchy
This sounds like a good use-case for the context api and a custom hook
You might also want to look at the parallel routes example, depending on what this will be used for
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes#modals
You might also want to look at the parallel routes example, depending on what this will be used for
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes#modals
5 Replies
SomaliOP
export const Button = ({
className,
intent
size,
children,
modalContent,
...props
}) => {
if (modalContent) {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<button
className={buttonStyles({ intent, size, className })}
{...props}
>
{children}
</button>
</Dialog.Trigger>
<Modal>{modalContent}</Modal>
</Dialog.Root>
);
} else if (props.href) {
return (
<Link
{...props}
className={buttonStyles({ intent, size, className })}
>
{children}
</Link>
);
} else {
return (
<button
{...props}
className={buttonStyles({ intent, size, className })}
>
{children}
</button>
);
}
};
'use client';
import React, { useState } from 'react';
import * as Dialog from '@radix-ui/react-dialog';
import XClose from '/public/icons/x-close.svg';
export const Modal = ({ children }) => {
return (
<Dialog.Portal>
<Dialog.Overlay className="DialogOverlay">
<Dialog.Close asChild>
<button
className=""
aria-label="Close"
>
<XClose />
</button>
</Dialog.Close>
</Dialog.Overlay>
<Dialog.Content className="DialogContent overflow-auto">
{children}
</Dialog.Content>
</Dialog.Portal>
);
};
This sounds like a good use-case for the context api and a custom hook
You might also want to look at the parallel routes example, depending on what this will be used for
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes#modals
You might also want to look at the parallel routes example, depending on what this will be used for
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes#modals
Answer
SomaliOP
hmm, context api with <Dialog> comp inside?
Sure. You could set the open/close state and the content as needed
SomaliOP
yes, that is good solution, thank you