# Dialog

<FrameworkCodeSwitcher>
  <div slot="astro">
```astro
---
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose } from "@/components/starwind/dialog";
import { Button } from "@/components/starwind/button";
---

<Dialog>
  <DialogTrigger asChild>
    <Button>Open Dialog</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Example Dialog</DialogTitle>
      <DialogDescription>
        This is a simple dialog example that demonstrates the basic functionality.
      </DialogDescription>
    </DialogHeader>
    <div class="py-4">Your dialog content goes here.</div>
    <DialogFooter>
      <DialogClose asChild>
        <Button variant="outline">Cancel</Button>
      </DialogClose>
      <Button>Save Changes</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
```
  </div>
  <div slot="react">
```tsx
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose } from "@/components/starwind/dialog";
import { Button } from "@/components/starwind/button";

export function Example() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open Dialog</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Example Dialog</DialogTitle>
          <DialogDescription>
            This is a simple dialog example that demonstrates the basic functionality.
          </DialogDescription>
        </DialogHeader>
        <div className="py-4">Your dialog content goes here.</div>
        <DialogFooter>
          <DialogClose asChild>
            <Button variant="outline">Cancel</Button>
          </DialogClose>
          <Button>Save Changes</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
```
  </div>
</FrameworkCodeSwitcher>

## Installation

```bash
npx starwind@latest add dialog
```

## Usage

### General Notes

All you really need is the `Dialog`,`DialogTrigger`, and `DialogContent`. The rest is up to you. As examples, the search feature and mobile navbar of this site are built on top of the Dialog component.

### With Form

Dialogs are commonly used with forms for data input.

> **Tip:** Open up the dev tools console to see the form data on submission.

```astro
---
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
  DialogClose,
} from "@/components/starwind/dialog";

import { Input } from "@/components/starwind/input";

import { Label } from "@/components/starwind/label";

import { Button } from "@/components/starwind/button";
---

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">Edit Profile</Button>
  </DialogTrigger>
  <DialogContent class="sm:max-w-[450px]">
    <form id="edit-profile-form" method="dialog" class="flex flex-col gap-4">
      <DialogHeader>
        <DialogTitle>Edit profile</DialogTitle>
        <DialogDescription>
          Make changes to your profile here. Click save when you're done.
        </DialogDescription>
      </DialogHeader>
      <div class="grid gap-4 py-4">
        <div class="grid grid-cols-4 items-center gap-4">
          <Label for="name-edit" class="text-right"> Name </Label>
          <Input id="name-edit" name="name" placeholder="Pedro Duarte" class="col-span-3" />
        </div>
        <div class="grid grid-cols-4 items-center gap-4">
          <Label for="username" class="text-right"> Username </Label>
          <Input id="username" name="username" placeholder="@peduarte" class="col-span-3" />
        </div>
      </div>
      <DialogFooter>
        <DialogClose asChild>
          <Button type="button" variant="outline">Cancel</Button>
        </DialogClose>
        <Button type="submit">Save changes</Button>
      </DialogFooter>
    </form>
  </DialogContent>
</Dialog>

<script>
  function handleFormSubmit() {
    const form = document.querySelector("#edit-profile-form") as HTMLFormElement;

    if (form) {
      form.addEventListener("submit", (e) => {
        e.preventDefault();
        const formData = new FormData(form);
        const formValues = Object.fromEntries(formData.entries());

        // demo form data logging
        console.log("Form submission values:", formValues);

        // You can add additional logic here like:
        // - Form validation
        // - API submission
        // - Success/error handling
      });
    }
  }

  handleFormSubmit();

  document.addEventListener("astro:after-swap", handleFormSubmit);
</script>
```

> **Info:** Dialog content now gets its transition timing from the Runtime component and stylesheet, so the legacy `animationDuration` prop is no longer needed.

### Multiple Triggers

You can have multiple triggers open the same dialog, including external triggers outside the Dialog wrapper. Add an `id` to `<Dialog />` and pass that ID through `targetId` on each external `<DialogTrigger />`.

```astro
---
import { Button } from "@/components/starwind/button";
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/starwind/dialog";
import { Input } from "@/components/starwind/input";
import { Label } from "@/components/starwind/label";
import { Textarea } from "@/components/starwind/textarea";
---

<Dialog id="contact-us-dialog">
  <DialogTrigger asChild>
    <Button variant="outline">Contact Us</Button>
  </DialogTrigger>
  <DialogContent class="sm:max-w-[450px]">
    <form id="contact-form" method="dialog" class="flex flex-col gap-4">
      <DialogHeader>
        <DialogTitle>Contact Us</DialogTitle>
        <DialogDescription>
          Send us a message and we'll get back to you shortly.
        </DialogDescription>
      </DialogHeader>
      <div class="grid gap-6 py-4">
        <div class="grid gap-2">
          <Label for="email">Email</Label>
          <Input id="email" name="email" type="email" placeholder="your@email.com" />
        </div>
        <div class="grid gap-2">
          <Label for="subject">Subject</Label>
          <Input id="subject" name="subject" placeholder="How can we help?" />
        </div>
        <div class="grid gap-2">
          <Label for="message">Message</Label>
          <Textarea
            id="message"
            name="message"
            placeholder="Tell us what you need..."
            class="min-h-[80px]"
          />
        </div>
      </div>
      <DialogFooter>
        <DialogClose asChild>
          <Button type="button" variant="outline">Cancel</Button>
        </DialogClose>
        <Button type="submit">Send Message</Button>
      </DialogFooter>
    </form>
  </DialogContent>
</Dialog>

<!-- External trigger that opens the same dialog -->
<div class="mt-8">
  <p class="text-muted-foreground mb-2 text-sm">
    This button is outside the Dialog component but opens the same dialog:
  </p>
  <DialogTrigger targetId="contact-us-dialog" class="mt-2" asChild>
    <Button variant="primary">Contact Us (External)</Button>
  </DialogTrigger>
</div>

<script>
  const setupForm = () => {
    const form = document.getElementById("contact-form") as HTMLFormElement;
    if (!form) return;

    form.addEventListener("submit", (e) => {
      e.preventDefault();
      const formData = new FormData(form);
      const formValues = Object.fromEntries(formData.entries());

      // demo form data logging
      console.log("Form submission values:", formValues);

      // You can add additional logic here like:
      // - Form validation
      // - API submission
      // - Success/error handling
    });
  };

  setupForm();

  document.addEventListener("astro:after-swap", setupForm);
</script>
```

> **Info:** External Runtime dialog triggers identify their dialog with `targetId`; the former `for` prop is no longer part of the styled trigger API.

### Nested Dialogs

<DocsBadge variant="info" text="New" size="md" class="mr-1" /> You can nest dialogs within other dialogs to create multi-level workflows. The nested dialog will appear on top of the parent dialog, and only the topmost dialog will close when pressing Escape or clicking outside.

```astro
---
import { Button } from "@/components/starwind/button";
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/starwind/dialog";
---

<Dialog>
  <DialogTrigger asChild>
    <Button variant="outline">Open Parent Dialog</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Parent Dialog</DialogTitle>
      <DialogDescription>
        This is the parent dialog. You can open a nested dialog from here.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter class="mt-4">
      <Dialog>
        <DialogTrigger asChild>
          <Button class="w-full sm:w-auto">Open Nested</Button>
        </DialogTrigger>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Nested Dialog</DialogTitle>
            <DialogDescription>
              This is the nested dialog. The parent will not close when clicking outside.</DialogDescription
            >
          </DialogHeader>
          <DialogFooter class="mt-4">
            <DialogClose asChild>
              <Button variant="outline">Close Nested</Button>
            </DialogClose>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      <DialogClose asChild>
        <Button variant="outline" class="w-full sm:w-auto">Close Parent</Button>
      </DialogClose>
    </DialogFooter>
  </DialogContent>
</Dialog>
```

## Framework Availability
Dialog is available for Astro and React.
Astro available; React available
| Framework | Status | Notes |
| --- | --- | --- |
| Astro | available | - |
| React | available | - |
## API Reference
### Dialog
- Inherits div attributes.

### DialogTrigger
| Prop | Type | Required | Default | Kind | Description |
| --- | --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `false` | Wrapper prop | Merges the component behavior and props into its child element. |
- Inherits button attributes.

### DialogContent
- Inherits dialog attributes.

### DialogHeader
- Inherits div attributes.

### DialogFooter
- Inherits div attributes.

### DialogTitle
- Inherits h2 attributes.

### DialogDescription
- Inherits p attributes.

### DialogClose
| Prop | Type | Required | Default | Kind | Description |
| --- | --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `false` | Wrapper prop | Merges the component behavior and props into its child element. |
- Inherits button attributes.
### Primitive And Runtime API
Behavior, state, events, form participation, and imperative methods are documented in the lower-level references.
- Primitive: [Dialog Primitive](/docs/primitives/dialog/)
- Runtime factory: [`createDialog`](/docs/runtime/#create-dialog) from `@starwind-ui/runtime/dialog`

## Changelog

### v2.0.0

- Rebuilt Dialog on Starwind Runtime for modal state, focus management, dismissal, and nesting.
- See the [Dialog Primitive](/docs/primitives/dialog/) for the underlying unstyled anatomy and behavior API.