ui
ui copied to clipboard
Feature: Close Functionality for Dialog Component
Right now there's no such wrapper code available in the docs for close functionality in Dialog component. I have tried to implement the same and it's working all fine.
const DialogClose = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Close>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Close
ref={ref}
{...props}
/>
))
DialogClose.displayName = DialogPrimitive.Title.displayName
This can be used like the snippet shown below
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</DialogDescription>
</DialogHeader>
<DialogFooter>
{/* this is how it can be used */}
<DialogClose />
</DialogFooter>
</DialogContent>
</Dialog>
Hope this helps! Happy to have a chat around this issue/feature-request.
@yashsehgal-clamp Yeah, that works fine, now, a better example can be:
<DialogFooter>
<DialogClose asChild>
<Button onClick={editTask}>Save changes</Button>
</DialogClose>
</DialogFooter>
Go ahead and send a PR, you could even create an example at https://ui.shadcn.com/docs/primitives/dialog showing how to close it from the footer
Sure, thanks for spending time on this issue. Really good work with all the other components, really helpful.
I will be raising a PR shortly 👍🏽
@yashsehgal could you apply this to sheets
as well?
Sheets are basically same as Dialogs
Thank you for this @yashsehgal
Sorry very new to this so hoping for some help. I have a react-hook-form form with a submit btn inside a dialog called from a dropdown. While I can add another button to close the form as suggested by @Angelfire I can't figure out how to make the form submit button submit the form and if validation successful close the dialog.
Thanks so much @yashsehgal!
I did some changes and made function if you want to call it on the onSubmit
I added an id in the close button: id="closeDialog"
const DialogContent = React.forwardRef<
// ...
<DialogPrimitive.Close
id="closeDialog"
className="..."
>
// ...
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
then exported a dialogClose()
const dialogClose = () => {
document.getElementById('closeDialog')?.click();
};
and now I can call this inside a function for example, after validating with zod a form
@conana28 @BielCoelho There is a way to close it on submit etc, it's described in the radix-ui docs here
const [open, setOpen] = useState(false)
<Dialog open={open} onOpenChange={setOpen}>
@BielCoelho @kaareloun Thanks for your help. Got both solutions working
Sorry very new to this so hoping for some help. I have a react-hook-form form with a submit btn inside a dialog called from a dropdown. While I can add another button to close the form as suggested by @Angelfire I can't figure out how to make the form submit button submit the form and if validation successful close the dialog.
I also have the same issues . dialog not closing onSubmit
I did some changes and made function if you want to call it on the onSubmit
I added an id in the close button:
id="closeDialog"
const DialogContent = React.forwardRef< // ... <DialogPrimitive.Close id="closeDialog" className="..." > // ... </DialogPortal> )); DialogContent.displayName = DialogPrimitive.Content.displayName;
then exported a
dialogClose()
const dialogClose = () => { document.getElementById('closeDialog')?.click(); };
and now I can call this inside a function for example, after validating with zod a form
This should be a feature.
Here is how we do it and it works great.
IF you are using shadcn-ui
- Wrap the element that you want to use to close the dialog with
DialogTrigger
- Pass
asChild
to theDialogTrigger
in 2 If you were thinking, "This is the same way you can open the dialog", you are correct!
But if you want to use radix
to close the dialog, you can import DialogClose
from @radix-ui/react-dialog
and it'll work the same. You just need to replace DialogTrigger
with DialogClose
.
<DialogTrigger asChild>
<Button>Close</Button>
</DialogTrigger>
THANKS SM BRO <3 @kaareloun
I did some changes and made function if you want to call it on the onSubmit
I added an id in the close button:
id="closeDialog"
const DialogContent = React.forwardRef< // ... <DialogPrimitive.Close id="closeDialog" className="..." > // ... </DialogPortal> )); DialogContent.displayName = DialogPrimitive.Content.displayName;
then exported a
dialogClose()
const dialogClose = () => { document.getElementById('closeDialog')?.click(); };
and now I can call this inside a function for example, after validating with zod a form
i did the same, just used ref instead
Thank you @yashsehgal-clamp!
This helped answer my question.
Here was my solution.
// import DialogPrimitive in your component using Dialog component
import * as DialogPrimitive from "@radix-ui/react-dialog"
<Dialog>
<DialogContent>
<DialogPrimitive.Close>
{/* add any element here to trigger dialog to close */}
</DialogPrimitive.Close>
</DialogContent>
</Dialog>
Hey @benyaminl ! You can add a prop & new interface type into your DialogContent in components/ui/dialog.tsx
that looks like this:
interface DialogContentProps {
showCloseButton: boolean;
className?: string;
children?: React.ReactNode;
}
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
DialogContentProps &
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ showCloseButton = true, className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
className
)}
{...props}
>
{children}
{showCloseButton ? (
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
) : (
''
)}
</DialogPrimitive.Content>
</DialogPortal>
));
I have added the showCloseButton
prop to the component, you can then simply pass in showCloseButton={true/false}
to show/hide the button 😄
Sorry very new to this so hoping for some help. I have a react-hook-form form with a submit btn inside a dialog called from a dropdown. While I can add another button to close the form as suggested by @Angelfire I can't figure out how to make the form submit button submit the form and if validation successful close the dialog.
I am looking for the same thing
For the commenters asking about how to control open/close:
Remember shadcn/ui is mostly a collection of tailwind styles for radix-ui components. Therefore you should check the radix-ui docs to understand how to control and manage the behaviour of their components.
Controlling open/close state
By default radix manages the open/close state of the dialog for you. However you also have the option to control the open/close state yourself and pass it to the Dialog via props. You can use this option if you want to close a dialog based on some external condition such as a form submission.
The docs refer to the choice as uncontrolled (default -- they control the state) vs. controlled (you control the state).
If you look at the shadcn/ui code for Dialog, it simply re-exports the underlying radix-ui Dialog.Root
as Dialog
without changing anything (i.e. shadcn/ui Dialog
is radix-ui's Dialog.Root
, it's only exported with a slightly different name). That means everything in the radix docs including all the examples fully apply to shadcn/ui.
To control Dialog.Root
you pass open
(boolean) and setOpen
callback via props (setOpen
is a useState callback that sets the value of open
).
Now that you control the state in your parent component you can change it however and whenever you like (such as when a form submission is successful) and the dialog will respond.
Examples
There are solid examples in the docs:
- https://www.radix-ui.com/primitives/docs/components/dialog#examples
- https://www.radix-ui.com/primitives/docs/components/dialog#close-after-asynchronous-form-submission
Here's a working EditDialog
component I created for a project I'm working on. It supports Zod validation in a form inside a shadcn <Dialog>:
import { PropsWithChildren, useState } from 'react'
import { UseFormReturn } from 'react-hook-form'
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle
} from '../../../ui/dialog'
import { Form } from '../../../ui/form'
import { Button } from '../../../ui/button'
export const EditDialog = ({
children,
form,
onSubmit,
triggerContainer
}: PropsWithChildren & {
form: UseFormReturn
onSubmit: (event) => void
triggerContainer: React.JSX.Element
}) => {
const [open, setOpen] = useState(false)
return (
<Dialog open={open} onOpenChange={setOpen}>
{triggerContainer}
<DialogContent className="sm:max-w-md">
<Form {...form}>
<form
onSubmit={form.handleSubmit((event) => {
onSubmit(event)
setOpen(false)
})}
>
<DialogHeader>
<DialogTitle>Add New Area</DialogTitle>
</DialogHeader>
{children}
<DialogFooter className="sm:justify-start pt-4">
<DialogClose asChild>
<Button type="button" variant="outline">
Cancel
</Button>
</DialogClose>
<Button type="submit">Save</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
)
}
The triggerContainer
element should contain a <DialogTrigger>
somewhere inside. Could be the root element, could be nested inside other elements. Just make sure there are no other <Dialog>
elements inside it. Form submission works both by pressing the button as well as the Enter
key.
Enjoy! :)
This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.