dialog
Compose a modal from a declarative invoker and native dialog. The browser owns
modal focus and disclosure; AngularTS owns form values and application actions.
<section class="dialog">
<button commandfor="profile-dialog" command="show-modal">Edit profile</button>
<dialog id="profile-dialog">
<header>
<h2>Edit profile</h2>
<p>Update your public profile.</p>
</header>
<button commandfor="profile-dialog" command="close">Save changes</button>
</dialog>
</section>
Profile Dialog
Example
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Dialog</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="profile={name:'Pedro Duarte',username:'@peduarte'}; savedName='Pedro Duarte'"
data-example="dialog-demo"
>
<main class="visual-example">
<section id="profile-dialog" class="dialog">
<button
commandfor="profile-dialog-content"
command="show-modal"
variant="outline"
>
Edit profile
</button>
<dialog
id="profile-dialog-content"
closedby="any"
aria-labelledby="profile-dialog-title"
aria-describedby="profile-dialog-description"
>
<header>
<h2 id="profile-dialog-title">Edit profile</h2>
<p id="profile-dialog-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<form method="dialog">
<label for="dialog-name">
<span>Name</span>
<input id="dialog-name" ng-model="profile.name" />
</label>
<label for="dialog-username">
<span>Username</span>
<input id="dialog-username" ng-model="profile.username" />
</label>
<footer>
<button
type="button"
commandfor="profile-dialog-content"
command="close"
variant="outline"
>
Cancel
</button>
<button
type="button"
commandfor="profile-dialog-content"
command="close"
ng-click="savedName=profile.name"
>
Save changes
</button>
</footer>
</form>
<button
type="button"
commandfor="profile-dialog-content"
command="close"
variant="ghost"
size="icon-sm"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
<span class="visually-hidden">Close</span>
</button>
</dialog>
</section>
<output class="dialog-output" aria-live="polite">
Saved profile: <span ng-bind="savedName"></span>
</output>
</main>
</body>
</html>
Close Controls
Corner and footer close actions are distinct, and the corner control can be omitted without changing modal behavior.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Dialog Close Workflows</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
data-example="dialog-close-button dialog-no-close-button"
>
<main class="dialog-workflow-grid visual-example">
<section class="dialog-workflow" aria-labelledby="share-heading">
<h2 id="share-heading">Custom close action</h2>
<div id="share-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="share-dialog-content"
command="show-modal"
>
Share
</button>
<dialog
id="share-dialog-content"
closedby="any"
aria-labelledby="share-dialog-title"
aria-describedby="share-dialog-description"
>
<header>
<h3 id="share-dialog-title">Share link</h3>
<p id="share-dialog-description">
Anyone who has this link will be able to view this project.
</p>
</header>
<div class="dialog-copy-row">
<input
aria-label="Share URL"
value="https://example.com/link/to/document"
readonly
/>
<button variant="secondary">Copy Link</button>
</div>
<footer>
<button
variant="outline"
commandfor="share-dialog-content"
command="close"
>
Close
</button>
</footer>
<button
variant="ghost"
size="icon-sm"
commandfor="share-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
<span class="visually-hidden">Close</span>
</button>
</dialog>
</div>
</section>
<section class="dialog-workflow" aria-labelledby="plain-heading">
<h2 id="plain-heading">Without corner close</h2>
<div id="plain-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="plain-dialog-content"
command="show-modal"
>
Open dialog
</button>
<dialog
id="plain-dialog-content"
closedby="any"
aria-labelledby="plain-dialog-title"
aria-describedby="plain-dialog-description"
>
<header>
<h3 id="plain-dialog-title">Terms of service</h3>
<p id="plain-dialog-description">
Review the current terms before continuing.
</p>
</header>
<p>Your workspace data remains available to members with access.</p>
<footer>
<button commandfor="plain-dialog-content" command="close">
Continue
</button>
</footer>
</dialog>
</div>
</section>
</main>
</body>
</html>
Scrolling
Use a section directly inside the native dialog or its form for scrollable
content, and add class="scroll-area" for native overflow. Keep the footer
outside that section when its actions must remain visible.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Dialog Scroll Workflows</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
data-example="dialog-scrollable-content dialog-sticky-footer"
>
<main class="dialog-workflow-grid visual-example">
<section class="dialog-workflow" aria-labelledby="scroll-heading">
<h2 id="scroll-heading">Scrollable content</h2>
<div id="scroll-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="scroll-dialog-content"
command="show-modal"
>
Read profile
</button>
<dialog
size="wide"
id="scroll-dialog-content"
closedby="any"
aria-labelledby="scroll-dialog-title"
aria-describedby="scroll-dialog-description"
>
<header>
<h3 id="scroll-dialog-title">About Pedro Duarte</h3>
<p id="scroll-dialog-description">
A short professional biography.
</p>
</header>
<section class="dialog-prose">
<p>
Pedro is a designer and developer focused on accessible design
systems and thoughtful product interfaces.
</p>
<p>
He works across interaction design, component architecture, and
documentation to make complex systems easier to use.
</p>
<p>
His projects explore how strong defaults and composable APIs can
support teams without limiting their visual language.
</p>
<p>
Outside product work, he studies typography, browser behavior,
and the details that make keyboard workflows feel dependable.
</p>
<p>
He has collaborated with distributed teams building tools for
creators, engineers, and operations specialists.
</p>
<p>
This final paragraph ensures the body has genuine overflow and
remains independently scrollable inside the viewport.
</p>
</section>
<button
variant="ghost"
size="icon-sm"
commandfor="scroll-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
<span class="visually-hidden">Close</span>
</button>
</dialog>
</div>
</section>
<section class="dialog-workflow" aria-labelledby="sticky-heading">
<h2 id="sticky-heading">Sticky footer</h2>
<div id="sticky-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="sticky-dialog-content"
command="show-modal"
>
Review notes
</button>
<dialog
size="wide"
id="sticky-dialog-content"
closedby="any"
aria-labelledby="sticky-dialog-title"
aria-describedby="sticky-dialog-description"
>
<header>
<h3 id="sticky-dialog-title">Release notes</h3>
<p id="sticky-dialog-description">
Review the changes included in this release.
</p>
</header>
<section class="dialog-prose">
<p>
Focus is now contained inside modal dialogs while they are open.
</p>
<p>
Background content becomes inert and document scrolling is
restored when the dialog closes.
</p>
<p>
Internal triggers receive generated relationships to their
directly owned dialog content.
</p>
<p>
Nested overlays no longer acquire controls belonging to a child
overlay root.
</p>
<p>
Scrollable bodies retain the header and footer in stable
positions throughout keyboard and pointer interaction.
</p>
<p>
Logical positioning keeps the corner close control aligned in
both left-to-right and right-to-left layouts.
</p>
</section>
<footer>
<button
variant="outline"
commandfor="sticky-dialog-content"
command="close"
>
Cancel
</button>
<button commandfor="sticky-dialog-content" command="close">
Confirm
</button>
</footer>
</dialog>
</div>
</section>
</main>
</body>
</html>
Right To Left
View source
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Dialog Rtl</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="profile={name:'محمد علي',username:'@mohamed'}"
data-example="dialog-rtl"
>
<main class="visual-example">
<section id="rtl-profile-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="rtl-profile-dialog-content"
command="show-modal"
>
تعديل الملف الشخصي
</button>
<dialog
id="rtl-profile-dialog-content"
closedby="any"
aria-labelledby="rtl-profile-dialog-title"
aria-describedby="rtl-profile-dialog-description"
>
<header>
<h2 id="rtl-profile-dialog-title">تعديل الملف الشخصي</h2>
<p id="rtl-profile-dialog-description">
غيّر بيانات ملفك الشخصي ثم احفظ التعديلات.
</p>
</header>
<section>
<label for="rtl-name">
<span>الاسم</span>
<input id="rtl-name" ng-model="profile.name" />
</label>
<label for="rtl-username">
<span>اسم المستخدم</span>
<input id="rtl-username" ng-model="profile.username" />
</label>
</section>
<footer>
<button
variant="outline"
commandfor="rtl-profile-dialog-content"
command="close"
>
إلغاء
</button>
<button commandfor="rtl-profile-dialog-content" command="close">
حفظ التغييرات
</button>
</footer>
<button
variant="ghost"
size="icon-sm"
commandfor="rtl-profile-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
<span class="visually-hidden">إغلاق</span>
</button>
</dialog>
</section>
</main>
</body>
</html>
Installation
Load the AngularCSS stylesheet. This entry needs no AngularCSS JavaScript or angular.css module dependency. Add AngularTS when using application bindings such as ng-model or ng-click. See Installation for the complete setup.
This entry uses native HTML and CSS. AngularCSS registers no runtime directive for it. Native dialog top-layer and modal behavior.
Anatomy
Root styling selector
.dialog
Semantic structure
Use .dialog as a composition wrapper containing a native invoker button and dialog. Close controls use command=close; semantic headers, sections, forms, and footers need no anatomy classes or nested AngularCSS attributes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
closedby | Authored | Native dialog dismissal behavior. |
command | Authored | Native invoker action such as show-modal or close. |
commandfor | Authored | ID of the native dialog controlled by an invoker. |
dir | Authored | Text and interaction direction: ltr or rtl. |
size | Authored | Dialog width: wide; omit for the default width. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
This styling hook does not define component-specific CSS custom properties.
DOM events
This component does not emit a component-specific custom event.
Native DOM events continue to work normally. AngularTS event directives such as
ng-click and ng-keydown, plus the data-change model callback, remain application-owned.
Behavior
A native dialog opened with command=show-modal owns top-layer rendering, modal focus, Escape, background isolation, and trigger focus restoration. Declarative command=close controls dismiss it. AngularTS remains responsible for form models, validation, submission, authored content, and application state.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Use a visible title and description connected with aria-labelledby and aria-describedby. Native modal dialogs contain focus, isolate the background, close on Escape, and restore focus to their declarative invoker.
Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.
Customization
Target semantic elements, native state selectors, and component classes with ordinary CSS. Behavior and accessible state remain with native HTML and AngularTS; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state variants, and iframe demo isolation.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.