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>
Installation
pnpx starwind@latest add dialog
npx starwind@latest add dialog
yarn dlx 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.
---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]" animationDuration={200}> <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>
Multiple Triggers
New You can have multiple triggers open the same dialog, including external triggers (triggers outside the Dialog wrapper). To use external triggers, you need to add an id
prop to the <Dialog />
component and pass the matching ID to the “for” prop of any extra <DialogTrigger />
elements you want to open the same dialog.
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> </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 for="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>
API Reference
Dialog
The root component that serves as a container for all dialog-related components. It manages the state of the dialog and handles keyboard interactions.
The component accepts all standard HTML attributes for <div>
elements.
DialogTrigger
The button that opens the dialog. When clicked, it shows the dialog content.
asChild
: When true, the component will render its child element instead of a button component.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
The component accepts all standard HTML attributes for <button>
elements.
DialogContent
The container for dialog content. This component renders the actual modal dialog with animation effects.
animationDuration
: Open and close animation duration in milliseconds.
Prop | Type | Default |
---|---|---|
animationDuration | number | 200 |
The component accepts all standard HTML attributes for <dialog>
elements.
DialogHeader
A container for dialog header content, typically containing a title and description.
The component accepts all standard HTML attributes for <div>
elements.
DialogFooter
A container for dialog footer content, typically containing action buttons.
The component accepts all standard HTML attributes for <div>
elements.
DialogTitle
A component for rendering the dialog title with appropriate styling.
The component accepts all standard HTML attributes for <h2>
elements except for id
, which is managed internally.
DialogDescription
A component for rendering the dialog description with appropriate styling.
The component accepts all standard HTML attributes for <p>
elements.
DialogClose
A button that closes the dialog when clicked.
asChild
: When true, the component will render its child element instead of a button component.
Prop | Type | Default |
---|---|---|
asChild | boolean | false |
The component accepts all standard HTML attributes for <button>
elements.
Changelog
v1.2.0
- Add support for multiple dialog opener buttons, including those outside the dialog wrapper. This is enabled by passing an ID to
<Dialog>
and passing the matching ID to the “for” prop of and extra<DialogTrigger />
elements you want to open the same dialog. - Remove “overflow-hidden” class from
<Dialog />
component initially and add it as a specific style in case it isn’t used elsewhere in the HTML (so that Tailwind does not optimize it out)
v1.1.3
- Fix exit animation
v1.1.2
- Ensure only the topmost dialog closes on interactions
v1.1.0
tailwind-variants
now implemented. This usestailwind-merge
under the hood to merge Tailwind classes without style conflicts, allowing you to override any existing classes using the “class” prop.