Skip to the content

Kongens Nytorv

Metro M1, M2 and M3.

Props

NameTypeDefaultDescription
title*ReactNode—The question, in sentence case, such as "Clear all filters?". Required: it names the alert dialog for screen readers.
description*ReactNode—One sentence under the title that says what answering does, such as "The map shows every line again.", read out with the name when it opens. Required. Phrasing content only: it renders in a <p>.
actions*ReactNode—The buttons that answer the question, such as Buttons, in a row at the alert dialog's end: Cancel first, which takes focus when it opens, and the confirming action last. An action closes the alert dialog by setting open to false, which calls no onClose. Required: with no close button, Cancel is the way out for touch screen readers.
triggerReactElement<unknown, JSXElementConstructor<any> | string>—The element that opens the alert dialog, such as a Button, rendered in place of the alert dialog. Focus returns to it when the alert dialog closes. Leave it out for an alert dialog opened only through open.
openboolean—Whether the alert dialog is open. Set it to control the alert dialog, with onClose to hear when it asks to close. An alert dialog whose actions must close it is controlled with open: a button in actions closes it only by setting open to false.
defaultOpenbooleanfalseWhether the alert dialog is open at first, when open is left out. Uncontrolled, its actions cannot close it, since they close it through open: it closes by Esc, or by Enter or Space on the trigger, which Shift+Tab reaches after a press on the backdrop among the page's other tabbable elements before the portal, so an alert dialog whose actions must close it is controlled with open instead.
onOpen(event: Event, details: AlertDialog.Root.ChangeEventDetails) => void—Called when the alert dialog asks to open, from its trigger. details is Base UI's, with its reason and cancel().
onClose(event: Event, reason: AlertDialog.Root.ChangeEventReason, details: AlertDialog.Root.ChangeEventDetails) => void—Called when the alert dialog asks to close, by Esc, with reason 'escape-key', or by Enter or Space on the trigger, which Shift+Tab reaches after a press on the backdrop among the page's other tabbable elements before the portal, with 'trigger-press'; details.cancel() keeps it open. A button in actions closes it through open and calls no onClose.
classNamestring—Reach the root, the popup. className is merged after pn-AlertDialog.
styleCSSProperties—Reach the root, the popup. className is merged after pn-AlertDialog.
refRef<HTMLDivElement>—Reach the root, the popup. className is merged after pn-AlertDialog.
slotProps{ trigger?: Props<unknown> | undefined; portal?: DialogPortalProps | undefined; backdrop?: DialogBackdropProps | undefined; title?: DialogTitleProps | undefined; description?: DialogDescriptionProps | undefined; }—Props for each part: trigger, portal, backdrop, title, description.
title (required)ReactNode, default —
The question, in sentence case, such as "Clear all filters?". Required: it names the alert dialog for screen readers.
description (required)ReactNode, default —
One sentence under the title that says what answering does, such as "The map shows every line again.", read out with the name when it opens. Required. Phrasing content only: it renders in a <p>.
actions (required)ReactNode, default —
The buttons that answer the question, such as Buttons, in a row at the alert dialog's end: Cancel first, which takes focus when it opens, and the confirming action last. An action closes the alert dialog by setting open to false, which calls no onClose. Required: with no close button, Cancel is the way out for touch screen readers.
triggerReactElement<unknown, JSXElementConstructor<any> | string>, default —
The element that opens the alert dialog, such as a Button, rendered in place of the alert dialog. Focus returns to it when the alert dialog closes. Leave it out for an alert dialog opened only through open.
openboolean, default —
Whether the alert dialog is open. Set it to control the alert dialog, with onClose to hear when it asks to close. An alert dialog whose actions must close it is controlled with open: a button in actions closes it only by setting open to false.
defaultOpenboolean, default false
Whether the alert dialog is open at first, when open is left out. Uncontrolled, its actions cannot close it, since they close it through open: it closes by Esc, or by Enter or Space on the trigger, which Shift+Tab reaches after a press on the backdrop among the page's other tabbable elements before the portal, so an alert dialog whose actions must close it is controlled with open instead.
onOpen(event: Event, details: AlertDialog.Root.ChangeEventDetails) => void, default —
Called when the alert dialog asks to open, from its trigger. details is Base UI's, with its reason and cancel().
onClose(event: Event, reason: AlertDialog.Root.ChangeEventReason, details: AlertDialog.Root.ChangeEventDetails) => void, default —
Called when the alert dialog asks to close, by Esc, with reason 'escape-key', or by Enter or Space on the trigger, which Shift+Tab reaches after a press on the backdrop among the page's other tabbable elements before the portal, with 'trigger-press'; details.cancel() keeps it open. A button in actions closes it through open and calls no onClose.
classNamestring, default —
Reach the root, the popup. className is merged after pn-AlertDialog.
styleCSSProperties, default —
Reach the root, the popup. className is merged after pn-AlertDialog.
refRef<HTMLDivElement>, default —
Reach the root, the popup. className is merged after pn-AlertDialog.
slotProps{ trigger?: Props<unknown> | undefined; portal?: DialogPortalProps | undefined; backdrop?: DialogBackdropProps | undefined; title?: DialogTitleProps | undefined; description?: DialogDescriptionProps | undefined; }, default —
Props for each part: trigger, portal, backdrop, title, description.

Use it

import { AlertDialog } from '@mylder/perron'

Ask your agent

get_reference({ library: "base-ui", component: "AlertDialog" })

Keyboard and ARIA

From the Base UI reference for AlertDialog and the installed useRenderDialogRoot, useDialogRoot, DialogPopup, DialogTitle and DialogDescription. "From" says who does it.

KeyDoesFrom
Enter, Space on the triggerOpen the alert dialog, calling onOpen with reason 'trigger-press', and move focus to the first tabbable element in the popup, the first button in actions, Cancel, unless initialFocus says otherwiseThe browser activates the button; Base UI opens and moves focus
Tab, Shift+TabMove focus through the buttons in actions, in reading order, wrapping from the last to the first and back while focus is in the popup. After a press on the backdrop, which moves focus to <body>, Tab lands on the last button in actions, the confirming one, and Shift+Tab reaches the page's tabbable elements before the portal, each behind the scrim and aria-hidden but focusable and operable: the trigger is one of them, and in the stories the only oneBase UI
Enter, Space on the trigger while openReached only by Shift+Tab after a press on the backdrop, past any tabbable element that follows the trigger on the page: close the alert dialog, calling onClose with reason 'trigger-press', focus staying on the triggerThe browser activates the button; Base UI closes
EscapeCloses the topmost alert dialog, calling onClose with reason 'escape-key', and returns focus to the triggerBase UI
Enter, Space on a button in actionsRun its onClick, in which the caller sets open to false, closing the alert dialog with no onClose; focus returns to the triggerThe browser activates the button; the caller acts and closes; Base UI returns focus

A press on the backdrop closes nothing, since Base UI's alert dialog has no outside-press dismissal, but it moves focus out of the popup to <body>, as the Tab row says.

ElementRoleAccessible name fromStates announced
triggerbutton, native, or the caller's element's ownIts own content, from the calleraria-haspopup="dialog", aria-expanded, from Base UI
rootalertdialog, from Base UIaria-labelledby the title; described by the description through aria-describedbyModal by Base UI hiding everything outside it with aria-hidden
titleheading, level 2, from the native <h2>Its text, the caller's titlenone
A button in actionsbutton, native, or the caller's element's ownIts own content, from the callerDisabled, when the caller disables it
backdroppresentation, from Base UInonenone
description, actionsnone: a plain <p> and a plain <div>nonenone

What axe won't catch, from the contract, each with how this component meets it:

  • Everything the eye is told, the ear is told, for every shape each prop accepts: the alert dialog is announced as an alert dialog with its title as its name and its description, the buttons in actions show their own words, and the scrim only dims what the aria-hidden outside the popup already removes.
  • Every landmark and named region has an accessible name: the alert dialog is named by its own heading, the title, through aria-labelledby, and title is required.
  • Every default label can be overridden: none here; AlertDialog owns no string, and every word, Cancel's included, is the caller's.
  • Every shape the type accepts renders, in every variant: title, description and actions render a string, an element and a list alike; a long word in the title or the description wraps, and the buttons in actions wrap onto more lines when the row is too narrow (CR-9).
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: none here; the closed alert dialog renders nothing, and Base UI hides the page behind the open one with aria-hidden.
  • Native semantics first: Base UI's alertdialog role, a native <h2> for the title, native <button>s for the trigger and the caller's Buttons in actions, and no ARIA of Perron's own.
  • Focus moves in reading order and returns on close: the title comes first in the DOM, then the description and the buttons in actions, Cancel first, as on screen; opening moves focus to Cancel, the answer that changes nothing, and closing, by Esc or by the caller's open, returns it to the trigger, also for an alert dialog open at first render (CR-5). After a press on the backdrop, Base UI moves focus to <body>, and the next Tab lands on the last button in actions, not on Cancel, and Shift+Tab reaches the page's tabbable elements before the portal, each aria-hidden but focusable and operable, the trigger among them (Keyboard and ARIA).
  • Every target is at least size.target-min square: the buttons in actions are the caller's, and a Button at its medium size is size.button (36 px) tall and wider than tall.
  • Loops stop when the system asks for less motion: none here; the alert dialog has no loop and no transition (CR-10).

Owned strings

No owned strings: every word is the caller's, through title, description, actions and trigger, Cancel's words included, as in Dialog's actions, so AlertDialog adds no key to packages/perron/src/locale/en.ts and takes no <key>Label prop.

Do and don't

For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.

RuleLevelDoDon'tChecked by
DD-1mustAsk one question in the title, in sentence case, such as "Clear all filters?", and say in the description what answering doesWrite a title that isn't a question, such as "Warning", or leave the consequence out: the person can't answer what they weren't askedreview
DD-2mustName the action by what it does, such as "Clear filters", and make it the one brand Button, last in actionsName it "OK" or "Yes": the button must say what pressing it does, read on its ownreview
DD-3shouldUse an alert dialog for an answer that must come before anything else, such as before clearing or removing somethingUse it for help, a form or a list: those are a Dialog's, which a press outside closesreview
DD-4mustPut Cancel first in actions, an outline neutral Button, so it takes focus when the alert dialog opens and Enter on its own changes nothingPut the action first, or set initialFocus to it: a stray Enter would act at oncereview
DD-5mustControl the alert dialog with open, and close it from each button's onClick by setting open to false, once the action's work is doneLeave Cancel out, disable it or hide it with a className: with no close button, it is the way out for touch screen readers, which have no Escreview
DD-6shouldPass the button that opens the alert dialog as trigger, so it is announced as opening a dialog and gets focus backOpen an alert dialog on its own, with no press from the person, to tell them something: a notice that needs no answer is an Alert or a Toastreview
DD-7shouldName Cancel by what it keeps when that reads better, such as "Keep filters", in the screen's localeAdd a close button or a second cancelling button to actions: Cancel and Esc already leave without actingreview
DD-8mustLet the alert dialog take z-index.dialog and its place in the middle of the screenSet a z-index, a position or an opacity on it: it would fall under another overlay or leave its scrimreview