ui: feat: function to trigger open/close dialog

Tried to search for it but didn’t find a way to close the dialog with a method or function. This is useful after processing data like - making a fetch request, mutation, or something that is awaitable, or can change dialog state from outside In the example below, let’s assume when the user clicks to “save changes”, I want to handle some submit function as a result close dialog from that function.

... await updateData(data).then(res=>closeDialog()).catch(err=>setError(error))

Currently, the way I see is used after exporting Close from radix primitive. But this is a JSX element, cant be used as function to change dialog state

<DialogClose>Close<<DialogClose/>
Screenshot 2023-05-20 at 09 37 14

There is 2nd way to close Dialog by creating a state and binding it to open={open} prop in the Dialog component. We can open or close Dialog by changing that state. But when do so, the “X” button and clicking outside of the dialog to close it stops working

Why we need that feature?

I think this will solve the issue we have in Note section which asserts that we have to encase the trigger button to Dialog itself. I take this as a big problem because if I have a Dialog component, it’s not possible to trigger it from multiple places. If I need to have that dialog in multiple places I need to copy/paste the same dialog code which is a duplication issue.

Sample use case: I have “Newsletter dialog” and I need to trigger this dialog with the button in the navbar, footer, or inside the main content. Or if the user stays for 5 mins on the website, I want to trigger that newsletter dialog

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 13
  • Comments: 22 (3 by maintainers)

Commits related to this issue

Most upvoted comments

If you want control the opening state by yourself, the open prop is the way to go, however, you also need to set the onOpenChange, so that the close button wiil able to trigger the onOpenChange event and change the state that you created.

Example:

const [open, setOpen] = useState(false);

return <Dialog open={open} onOpenChange={setOpen} />

Reference: https://www.radix-ui.com/docs/primitives/components/dialog#root

@OsamaQureshi147 For a basic requirement, you can probably use the searchParams and do a condition like:

/some-page?productId=69&modal=true

export default function Page({
  searchParams,
}: {
  searchParams: { [key: string]: string | string[] | undefined }
}) {
  const { productId, modal } = searchParams

  return (
    <div>
      <h1>Some Page</h1>
      <YourDialog open={modal === "true"} productId={productId} />
    </div>
  )
}

Then use <Link href="/some-page" /> to dismiss the modal.

Other than that, client component.

Demo:

https://github.com/shadcn-ui/ui/assets/13049130/d107ec0a-e6a4-45eb-a1be-839b74a5efc4

@OsamaQureshi147 It seems like you need JS on client side to me tho, this is the time where you have to use client component instead.

{!form.formState.isValid ? ( <Button type="submit" className="w-full"> Save changes </Button> ) : ( <DialogClose asChild> <Button type="submit" className="w-full"> Save changes </Button> </DialogClose> )}

this worked for me 😃

This is how we can do, hope it helps

"use client";
// Imports here

export function AddProductModal() {
  const router = useRouter();
  const [open, setOpen] = useState(false);

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button
          className="bg-red-50 text-red-600"
        >
          Add Product
        </Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[425px]">
         // ADD PRODUCT FORM HERE
        <DialogFooter>
          <Button
            onClick={() => {
              addProduct(data).then(() => setOpen(false));
              router.refresh();
            }}
            className="bg-red-50 text-red-600 hover:bg-red-100"
            type="submit"
          >
            Add
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

I’m actually trying a different approach (https://github.com/chungweileong94/nextjs-parallel-route-dialog) by using the NextJS parallel route to control the dialog open state. The thing that I focus in my code example is to preserve the dialog closing animation.