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
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 ...
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.
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
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:
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