Dialog
A modal dialog for a focused task or a confirmation before an irreversible action, such as deleting a project. Opens and closes from markup: commandfor plus command="--open" or command="--close".
Intents
overlay
modal
dismissible
Examples
Each one rendered live, over the markup that produces it.
Confirm a destructive action
Opened and closed from markup. Submitting the form closes it.
<aihio-button commandfor="confirm-delete" command="--open" variant="destructive">Delete project</aihio-button>
<aihio-dialog id="confirm-delete">
<aihio-dialog-header>
<aihio-dialog-title>Are you sure?</aihio-dialog-title>
<aihio-dialog-description>This action cannot be undone.</aihio-dialog-description>
</aihio-dialog-header>
<form method="post">
<aihio-dialog-footer>
<aihio-button commandfor="confirm-delete" command="--close" variant="outline">Cancel</aihio-button>
<aihio-button type="submit" variant="destructive">Delete</aihio-button>
</aihio-dialog-footer>
</form>
</aihio-dialog>
Mistakes
Each one beside its fix, with what aihio lint says about it. The prompt fragment gives agents the
same pairs, and the build fails if the linter stops catching one or a fix stops passing.
Missing header and footer.
Provide aihio-dialog-title for a name and aihio-dialog-footer for actions.
Don't
<aihio-dialog open><p>Delete?</p></aihio-dialog>
aihio lint reports
-
dialog-accessible-nameerror
Do
<aihio-dialog id="delete-project-dialog">
<aihio-dialog-header>
<aihio-dialog-title>Delete project?</aihio-dialog-title>
</aihio-dialog-header>
<aihio-dialog-footer>
<aihio-button commandfor="delete-project-dialog" command="--close" variant="outline">Cancel</aihio-button>
<aihio-button variant="destructive">Delete</aihio-button>
</aihio-dialog-footer>
</aihio-dialog>
Dialogs must not be nested.
Close the current dialog before opening another.
Don't
<aihio-dialog><aihio-dialog><p>Nested</p></aihio-dialog></aihio-dialog>
aihio lint reports
-
invalid-childerror -
dialog-accessible-nameerror -
dialog-accessible-nameerror
Do
Step 1
Step 2
<aihio-dialog id="first-step" aria-label="Step 1"><p>Step 1</p></aihio-dialog>
<aihio-dialog id="second-step" aria-label="Step 2"><p>Step 2</p></aihio-dialog>
Built-in commands such as show-modal only act on a native <dialog>, and this one is inside the component's shadow root, so nothing happens.
Use command="--open".
Don't
<aihio-button commandfor="confirm" command="show-modal">Delete</aihio-button>
<aihio-dialog id="confirm" aria-label="Confirm delete"></aihio-dialog>
aihio lint reports
-
invalid-commanderror Suggestscommand="--open"
Do
Delete this project?
<aihio-button commandfor="confirm" command="--open">Delete</aihio-button>
<aihio-dialog id="confirm" aria-label="Confirm delete"><p>Delete this project?</p></aihio-dialog>
API
Every attribute, property, method, and event the schema declares for aihio-dialog.
Attributes
open-
boolean
default
false - Whether the dialog is open
Methods
open(): void- Opens the dialog modally in the browser top layer.
close(options?: { restoreFocus?: boolean; reason?: string }): void- Requests that the dialog close.
Events
aihio-open- Fired after the dialog opens.
aihio-close-
detail
{ reason: string } - Fired after the dialog closes.
aihio-before-close-
detail
{ reason: string }cancelable - Cancelable request fired before the dialog closes.
Commands
Sent from markup: <aihio-button commandfor="id" command="…">, or a plain
<button> with the same attributes.
--open- Opens the dialog modally. Focus returns to the invoking button when it closes.
--close- Requests that the dialog close, with reason "command";
aihio-before-closecan still cancel it. --toggle- Opens the dialog when it is closed and closes it when it is open.
Composition
- Allowed children
-
aihio-dialog-headeraihio-dialog-footerother HTML
Sub-components
Used only inside aihio-dialog, which gives them their roles and keyboard behaviour.
<aihio-dialog-header>
Dialog header container
<aihio-dialog-title>
Dialog title text
<aihio-dialog-description>
Dialog description text
Accessibility
What you have to provide, and what the component already does. The obligations with a rule are checked by
aihio lint and by the dev build's console warnings.
Your obligations
-
error When dialog has noaihio-dialog-titleProvide aria-label on
aihio-dialogdescribing the dialog's purpose; otherwise screen readers announce an unnamed dialog.Checked as
dialog-accessible-name -
warn When dialog confirms a destructive actionLabel the confirming button with
variant="destructive"and keep Cancel as the first focusable control.Not machine-checkable: a judgment for the author.
Handled for you
- The native
<dialog>panel supplies dialog semantics, and showModal() supplies modality - aria-labelledby is wired to
aihio-dialog-titlewhen present - aria-describedby is wired to
aihio-dialog-descriptionwhen present - Native modal dialog behavior makes the document outside the dialog inert and contains keyboard focus
- A trigger and a Cancel button work from markup alone: commandfor plus
command="--open"orcommand="--close"needs no script - Opening focuses an authored autofocus element, otherwise the first rendered tab stop — never a hidden field or an unselected tab — and Tab wraps between the first and last rendered tab stops
- Escape closes the dialog
- Focus is restored to the trigger on close
- A shared overlay lock prevents concurrent dialogs from restoring page scroll too early
In patterns
Canonical compositions that use aihio-dialog.