On this page
Import
import { Dialog, DialogClose } from '@envsemble/envui';
Usage
A Dialog opens from its trigger, such as a Button, and holds its title, which names it, a description, its content as children, and its own actions, after the built-in close button, with the primary action last.
closeLabelnames the close button; name it Cancel for a decision.- Leave it uncontrolled, or control it with
openandonOpenChange, which receives the requested state and why: the trigger, Esc, an outside press, the close button or a DialogClose. defaultOpenopens it on the first render.
import { Button, Dialog, DialogClose, Text } from '@envsemble/envui';
export default function ProjectDetails() {
return (
<Dialog
trigger={<Button variant="secondary">View project</Button>}
title="Northwind launch"
description="Owned by Priya Shah · Due 14 November"
actions={<DialogClose variant="primary">Open project</DialogClose>}
>
<Text>
Plans, milestones and responsibilities for the launch, shared with everyone in the
workspace.
</Text>
</Dialog>
);
}Pending work
pending keeps the dialog open until it returns to false: Esc, outside presses and the close buttons don't dismiss it.
- It disables the built-in close button and every DialogClose inside.
- The last action, the primary one, shows it pending, where it is a Button that sets no
pendingof its own. - Put a
<form>inchildrenand make the primary action its submit button, through theformattribute, so Enter in a field submits it too.
<Dialog
title="Rename project"
closeLabel="Cancel"
pending={saving}
actions={
<Button type="submit" form={formId}>
Save name
</Button>
}
>
<form id={formId} onSubmit={save}>
<TextField label="Project name" readOnly={saving} />
</form>
</Dialog>
Closing actions
An action closes the dialog only where it is a DialogClose, a Button that closes it after its own onClick, or where it sets open to false. DialogClose takes Button's props and is secondary by default.
<Dialog
title="Save changes to Launch plan?"
closeLabel="Cancel"
actions={
<>
<DialogClose onClick={discard}>Don’t save</DialogClose>
<DialogClose variant="primary" onClick={save}>
Save
</DialogClose>
</>
}
/>
Placement, width and modal
placement is center, the default, or top, near the top of the window, so results grow down without moving the field.
widthismd, 28 rem and the default, orlg, 44 rem. Both narrow to fit the window.- By default the dialog is modal: it traps focus over a backdrop, hides the page from assistive technology, blocks presses on it and locks its scroll.
modal={false}leaves the page usable beside the dialog, such as an inspector. disablePointerDismissalkeeps it open on presses outside it, and a non-modal one also when focus moves outside.
<Dialog width="lg" title="Review changes" trigger={<Button>Review</Button>}>
…
</Dialog>
Focus
initialFocus sets where focus goes on opening, as a ref or a function of how it was opened; by default the first focusable element inside, and a confirmation's close button. finalFocus sets where it goes on closing, such as the row that opened it, where the trigger is gone or something other than trigger opened the dialog.
Composition
Keep one task per dialog: show a field's error on the field rather than in a second dialog over the first.
Customize
The parts are the surface, env-dialog, its heading, env-dialog-heading, with the title, env-dialog-title, the description, env-dialog-description, and the actions, env-dialog-actions, which start with the close button. The backdrop behind a modal dialog is env-dialog-backdrop.
The surface takes the popups' color and their shadow, --env-popup-shadow, as Popover describes, with no edge in light and their faint hairline in dark. It stays solid over the backdrop, so --env-popup-opacity and --env-popup-blur don't reach it. At high contrast, with reduced transparency and under forced colors it has no shadow and its level-3 elevation edge returns.
Accessibility
You provide
- A
title, and adescriptionwhere the consequence needs saying. closeLabelin the page's language, such as Cancel.finalFocuswhere the trigger is gone, or something other thantriggeropened the dialog.
envUI provides
role="dialog", named bytitleand described bydescription.- Focus moved in on open, kept inside a modal dialog and returned on close; a confirmation starts on its close button.
- The page behind a modal dialog hidden from assistive technology, closed to presses and locked from scrolling.
- A close button in every dialog, for touch screen readers that have no Esc.
Props
Dialog
A focused task over the page: a centered modal, or a modal near the top of the window. It has a title, an optional description, content and actions that start with a built-in close button. Base UI's dialog owns focus, Escape and outside presses. className, style, ref and data attributes go to the dialog's surface.
| Prop | Type | Description |
|---|---|---|
open | boolean | Whether the dialog is open, for a dialog the application controls with onOpenChange. |
defaultOpenDefault false | boolean | Whether a dialog the application doesn't control is open on the first render. |
onOpenChange | ( | Called with the requested state, and why, when the dialog asks to open or close: from the trigger, Escape, an outside press, the close button or a DialogClose. Not called for a dismissal that pending blocks. |
trigger | ReactElement | The element that opens the dialog, such as a Button. It reports the dialog it opens, and focus returns to it on close. Omit it for a dialog the application opens with open. |
titlerequired | ReactNode | The dialog's heading and accessible name, such as “Delete project?”. |
description | ReactNode | Muted text under the title that describes the dialog to assistive technology too, such as what its action changes. |
children | ReactNode | The content between the heading and the actions, such as text, fields or a list. |
actions | ReactNode | The dialog's own actions, after the built-in close button, with the primary action last. They close the dialog only where they are DialogClose or set open to false. While the dialog is pending, the last one shows it, where it is a Button that sets no pending of its own. |
closeLabelDefault 'Close', or EnvUIProvider's messages.dialog.close | string | The label of the built-in close button that starts the actions, such as Cancel. |
placementDefault 'center' | 'center''top' | center for a modal in the middle of the window; top for a modal near the top of the window for search-like tasks, so results grow downward without moving the field. For a panel at an edge of the window, use Sheet. |
widthDefault 'md' | 'md''lg' | md, 28 rem wide, or lg, 44 rem, for content-heavy dialogs such as tables, comparisons and longer forms. Both narrow to fit the window. |
modalDefault true | boolean | true traps focus in the dialog over a backdrop, hides the page from assistive technology, blocks presses on it and locks its scroll. false leaves the page usable beside the dialog; it then closes when focus or a press goes outside it, unless disablePointerDismissal. |
disablePointerDismissalDefault false | boolean | Keep the dialog open on presses outside it, and a non-modal dialog also when focus moves outside. Escape and the close buttons still close it. |
initialFocus | DialogFocusTarget | The element to focus when the dialog opens, as a ref or a function of how it was opened. By default focus moves to the first focusable element inside, such as the first field, or to the dialog itself when opened by touch. |
finalFocus | DialogFocusTarget | The element to focus when the dialog closes, such as the row that opened it. By default focus returns to the trigger, or to the element that had focus when the dialog opened. |
pendingDefault false | boolean | Work started from the dialog is in progress. Escape, outside presses and the close buttons cannot dismiss it until pending returns to false: the built-in close button and every DialogClose inside are disabled, the primary action, the last of actions, shows it pending, and the dialog reports busy. |
skeletonDefault false | boolean | Shows it and its content as a busy skeleton while that loads; turning it on or off renders the content anew. |
Also accepts the native props of <div>, such as ref, className and aria-* attributes.
DialogClose
A button inside a Dialog or a Sheet that closes it after its own onClick, for an action other than the built-in close button, such as Don't save or Done. It takes Button's props and is secondary by default, and is disabled while the dialog or sheet is pending.
| Prop | Type | Description |
|---|---|---|
variantDefault 'secondary' | 'primary''secondary''outline''ghost''text' | The emphasis, as Button's; secondary by default, as an action beside the dialog's main one. |
toneDefault 'neutral' | 'neutral''danger''accent' | The meaning: neutral for most actions, danger for one that deletes or ends something, and accent, on a primary only, for a main action that must stand apart from the brand blue. |
underlineDefault false | boolean | Show an underline for the text variant. |
size | 'sm''md''lg' | The control height, sm, md or lg; without it, the container's, and else md. |
fullWidthDefault false | boolean | Fill the width of the container, such as the actions of a narrow form stacked in a column. |
startIcon | ReactNode | A decorative icon before the label, such as IconAdd. |
endIcon | ReactNode | A decorative icon after the label, such as a ChevronRight for a next step. |
end | ReactNode | Quiet content at the far end, such as a shortcut's Kbd, with aria-hidden on its keys and aria-keyshortcuts on the button. |
pendingDefault false | boolean | Its work is running: a spinner turns over it, it keeps its width and name, and presses do nothing. |
Also accepts the native props of <button>, such as ref, className and aria-* attributes.
Part names
Each part's class and state attributes are public and versioned, for an application's CSS to style.
env-dialog- The dialog.
env-dialog-actions- The row of actions at the bottom.
env-dialog-backdrop- The backdrop behind a modal dialog.
env-dialog-content- The dialog's content between the header and the actions.
env-dialog-description- The sentence under the title.
env-dialog-header- The row with the title and the close button.
env-dialog-heading- The column with the title and the description.
env-dialog-positioner- The positioner that centres the dialog.
env-dialog-surface- The dialog's surface.
env-dialog-title- The title.
data-ending-style- Any value, or present on env-dialog, env-dialog-backdrop
data-env-skeleton- Present
data-placementcenter·topon env-dialog, env-dialog-positionerdata-starting-style- Any value, or present on env-dialog, env-dialog-backdrop
data-tonedanger·neutraldata-widthlg·md
Strings
EnvUIProvider's messages overrides each, and a component's own label prop wins over it.
messages.dialog.close"Close"The built-in close button's label.messages.dialog.resize"Resize"Names the handle that resizes a resizable side Sheet.messages.dialog.width({ width }) => stringThe resize handle's value: the Sheet's width in rem, such as 24 rem, in the locale's digits.
Changelog
- 1.0.0
width(mdorlg) forsize; the side panel,placement="right", is Sheet;onOpenChangereports the reason;initialFocusandfinalFocustake functions too; the surface's class isenv-dialog. The page isdialog, after the component.- 1.0.0-prerelease.6
A dialog fades in with
--env-motion-ease-enter, so it shows from its first frames rather than late, while it rises into place as before.While a dialog is
pending, every DialogClose inside is disabled as the built-in close button is, and its last action, where it is a Button that sets nopendingof its own, shows it pending, sopendingneed not be set on each.In dark, the backdrop is black at 70 %, rather than 50 %, so it sets the dark page back as clearly as the light backdrop does.
- 1.0.0-prerelease.5
Dialogs take the popups' color and soft shadow, with no outline edge, and stay solid over the scrim; at high contrast and with reduced transparency the shadow goes and the edge returns.