Dialog
---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>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> );}Installation
pnpx starwind@latest add dialognpx starwind@latest add dialogyarn dlx starwind@latest add dialogFramework Availability
Astro Available React AvailableDialog is available for Astro and React.
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.
---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>Runtime example adjustment
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 />.
This button is outside the Dialog component but opens the same dialog:
---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>Runtime example adjustment
External Runtime dialog triggers identify their dialog with targetId; the former for prop is no longer part of the styled trigger API.
Nested Dialogs
New 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.
---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>API Reference
Styled Component API
These props are added or materially changed by the installed Astro styled component. Standard HTML attributes remain available through the inherited interfaces noted below. Follow the Primitive and Runtime links for lower-level behavior props.
Dialog Trigger
Inherits button attributes.
Contains the following additional props:
asChild boolean false
- Description
- Merges the component behavior and props into its child element.
- Classification
- Wrapper prop
Dialog Close
Inherits button attributes.
Contains the following additional props:
asChild boolean false
- Description
- Merges the component behavior and props into its child element.
- Classification
- Wrapper prop
Primitive And Runtime API
Use these references when you need the lower-level behavior APIs behind Dialog.
Primitive API
Runtime API
- Dialog primitive
createDialogfrom@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 for the underlying unstyled anatomy and behavior API.