shadcn Dialog - "submit" vs "cancel"

I am working with a shadcn dialog and I want to execute different functionality when different actions happen. Specifically, I have a form in the modal and I have a save button, which I obviously want to make an API call. However, you can also close the modal by clicking on the backdrop and the built in close button. I want to be able to reset my form when I select the backdrop/close button and execute the API call on click of the save button. As far as I know, theres no way to distinguish between the method of closing the Dialog, any ideas?
4 Replies
tyler4949
tyler4949OP2mo ago
I have this post on the github for more info: https://github.com/shadcn-ui/ui/discussions/5588
GitHub
Distinguish between manual close vs cancel of Dialog component · sh...
I have a Dialog with a form inside using TanStack Form. I have an apply button which essentially just closes the modal. However I would like to reset the form when either clicking the Dialog close ...
showduhtung
showduhtung2mo ago
Few things I've done to achieve what you're looking for 1. Clear the form when form unmounts- which will happen either when the dialog closes naturally, or the form saves, and you close it manually. So a simple `useEffect(() => () =>form.clear(), []) 2. Created a ControlledDialog, which is a wrapper around Dialog, that passes a context with values of open state and a toggle close function to children. So when the form is completed and saved, I'll toggle it close. This decouples submit/cancel from the dialog's close behavior.
Rohit Luni
Rohit Luni2mo ago
export function MyDialog() { const [isOpen, setIsOpen] = useState(false); const [isFormSubmitted, setIsFormSubmitted] = useState(false); const { register, handleSubmit, reset } = useForm(); // Handle form submission const onSubmit = async (data) => { setIsFormSubmitted(true); await fetch("/api/save", { method: "POST", body: JSON.stringify(data), }); setIsOpen(false); // Close the dialog after submission }; // Handle dialog close const onOpenChange = (open) => { if (!open && !isFormSubmitted) { reset(); // Reset the form if the dialog is closed manually } setIsOpen(open); setIsFormSubmitted(false); // Reset the flag }; return ( <Dialog open={isOpen} onOpenChange={onOpenChange}> <Button onClick={() => setIsOpen(true)}>Open Dialog</Button> <DialogContent> <DialogHeader> <DialogTitle>My Form</DialogTitle> </DialogHeader> <form onSubmit={handleSubmit(onSubmit)}> <input {...register("name")} placeholder="Name" /> <DialogFooter> <Button type="submit">Save</Button> </DialogFooter> </form> </DialogContent> </Dialog> ); } this might work
tyler4949
tyler4949OP4w ago
I forgot to mention I am also adding the item to a list behind the scenes (so it can be tracked in the field array of the form - using tanstack form) that I also have to remove if I "cancel" the modal in addition to clearing the form. I did find these toggles in the radix docs, which solves the problem:
onInteractOutside={onCancel}
onEscapeKeyDown={onCancel}
onPointerDownOutside={onCancel}
onInteractOutside={onCancel}
onEscapeKeyDown={onCancel}
onPointerDownOutside={onCancel}
These are on the DialogContent instead of the Dialog which is why I missed it. I appreciate your thoughts though. I actually like the approach of only executing certain logic based on the onOpenChange value. I will look into that approach as well

Did you find this page helpful?