Dialog with multiple Trigger
's
#1532
-
The docs explain how to abstract a Dialog so it can be reused like this: export default () => (
<Dialog>
<DialogTrigger>Dialog trigger</DialogTrigger>
<DialogContent>Dialog Content</DialogContent>
</Dialog>
); In my use-case, I have multiple Although I can abstract this away, it is a tad cumbersome. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 5 replies
-
Yes, there're a couple of ways: const [isVisible, toggleVisibility] = useReducer(s => !s, false)
return (
<>
<button onClick={toggleVisibility}>Open Modal</button>
<MyDialog open={isVisible} onOpenChange={toggleVisibility} />
</>
) ... function MyDialog({ props: {} & React.ComponentProps<typeof DialogPrimitive.Root> }) {
if (!open) return null;
return (
<Dialog.Root {...props}>
{/* without the trigger */}
<Dialog.Portal>...</Dialog.Portal>
</Dialog.Root>
)
} As you may need to use it in different components, you may want to add function MyApp() {
const store = useStore()
return (
<>
<MyDialog open={store.isDialogVisible} onOpenChange={store.hideModal} />
...
</>
)
} However my prefered way is to use URL state because I guess it's a better UX and a cleaner solution. To open a UserProfileModal for example, you would do something like function MyApp() {
const router = useRouter();
return (
<>
<MyDialog open={!!router.query.profile} onOpenChange={() => router.push('/')} />
...
</>
)
} More details of this pattern can be found here. Although it's for Nextjs, the concept can be applied to other frameworks as well. |
Beta Was this translation helpful? Give feedback.
-
Although it might look like multiple triggers would be supported, it is not. The solution we would recommend isn't far though. The key is that instead of thinking of reusing a single "instance", think about reusing components instead. Here's an old demo showing the same principle with a reused "content": https://codesandbox.io/s/reused-dialogcontent-0oikl You could abstract the whole Dialog if you wanted to as well: function DeleteProductDialog(props) {
return (
<Dialog.Root {...props}>
{children}
<Dialog.Portal>
{/* all the content for this specific product dialog*/}
</Dialog.Portal>
</Dialog.Root>
)
} // somewhere
<DeleteProductDialog>
<Dialog.Trigger>Delete this product</Dialog.Trigger>
</DeleteProductDialog>
// someplace else
<DeleteProductDialog>
<Dialog.Trigger>Delete</Dialog.Trigger>
</DeleteProductDialog> You can do anything you want as they're just standard React components, the key is to think about composition/reuse of components, rather than reusing single instances. ✌️ |
Beta Was this translation helpful? Give feedback.
Although it might look like multiple triggers would be supported, it is not.
If you think about it, it doesn't make much sense, as accessibility also belongs to the trigger, so unfortunately the solution proposed by @gabrielmlinassi isn't great for that reason.
The solution we would recommend isn't far though. The key is that instead of thinking of reusing a single "instance", think about reusing components instead.
Here's an old demo showing the same principle with a reused "content": https://codesandbox.io/s/reused-dialogcontent-0oikl
You could abstract the whole Dialog if you wanted to as well: