Dialog
Usage
Dialog presents one modal task above the page. It uses the native <dialog> element, so it traps focus, locks the page behind a backdrop, and returns focus to the element that opened it. Pair it with DialogHeader to get a focusable title, an optional subtitle, and a close button.
<script setup lang="ts">
import { Button } from '@astryx-vue/core/Button'
import { Dialog, DialogHeader } from '@astryx-vue/core/Dialog'
import { ref } from 'vue'
const isOpen = ref(false)
</script>
<template>
<Button label="Share project" variant="secondary" @click="isOpen = true" />
<Dialog :is-open="isOpen" @open-change="isOpen = $event">
<DialogHeader title="Share project" has-close-button @open-change="isOpen = $event" />
<p>Copy the link and send it to your team.</p>
</Dialog>
</template>Best practices
| Guidance | Practices |
|---|---|
| Do | Choose the right purpose: info for dismissable content, form to prevent accidental backdrop dismissal, required when the user must respond. |
| Do | Include a clear title in the header so users immediately understand what the dialog is asking. |
| Do | Use purpose="form" for dialogs with inputs so the user can't accidentally lose data by clicking the backdrop. |
| Do | Keep dialogs focused on a single task; if the content grows beyond what fits, consider a full page instead. |
| Don't | Use a dialog for simple messages that could be shown inline or as a toast notification. |
| Don't | Nest dialogs inside other dialogs; restructure the flow into steps within a single dialog instead. |
| Don't | Use the fullscreen variant for simple confirmations; it is meant for complex content like editors or long forms. |
Examples
Basic
A header with a subtitle and close button. The title receives focus when the dialog opens.
Form
purpose form allows Escape but ignores backdrop clicks, so typed input is not lost by accident.
Required
purpose required disables Escape and backdrop dismissal. The dialog uses alertdialog semantics for decisions the user must make.
Fullscreen
variant fullscreen fills the viewport for long editing tasks and respects safe-area insets.
Imperative
useImperativeDialog opens content without managing isOpen. Render its Host once in the template.
Accessibility
Dialog is built on the native <dialog> element, so the modal behavior, the focus trap, and the focus handoff on close all come from the browser rather than from extra configuration.
The dialog is shown with showModal(), which makes the rest of the page inert while it is open. When it opens, initial focus goes to the first element with data-autofocus; if no element has that attribute, focus goes to the DialogHeader title.
The dialog takes its name from the DialogHeader title, which the component associates with the dialog through aria-labelledby. An explicit aria-label or aria-labelledby replaces that name with the one you provide.
Escape and backdrop clicks do not close the dialog directly. They emit openChange(false), and the parent decides whether to close. When the dialog closes, focus returns to the element that was focused when it opened, as long as that element is still in the page.
Limitations
Two constraints shape what you can put inside a dialog, and both are worth knowing before you combine it with other components.
- Tooltip and Popover render into
body. Inside an openDialogthey sit beneath the modal top layer, so they cannot be seen or used. Do not nest them inside a dialog until they are moved into the dialog's own layer. - Dialogs cannot be nested. If a flow needs several steps, restructure it as steps within a single dialog rather than opening a second one.
Layout
The standard variant sizes itself with width and maxHeight, and clamps to the viewport with spacing gutters on narrow screens. position places it at a static offset. Logical start and end offsets mirror under RTL.