Opinionated compositions assembled from elements, patterns, and components.
This is the multi-page printable view of this section. Click here to print.
Recipes
- 1: alert-dialog
- 2: application-shell
- 3: data-table
- 4: date-picker
- 5: drawer
- 6: form-layout
- 7: master-detail
- 8: sheet
1 - alert-dialog
Use alert dialog parts for destructive or confirmation flows that need a clear action and cancel target.
<section>
<button commandfor="delete-dialog" command="show-modal">
Delete project
</button>
<dialog id="delete-dialog" role="alertdialog" closedby="closerequest">
<h2>Delete project?</h2>
</dialog>
</section>
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 Alert 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
data-example="alert-dialog-basic alert-dialog-demo"
>
<section id="confirmation-dialog" class="visual-example">
<button
type="button"
commandfor="confirmation-dialog-content"
command="show-modal"
variant="outline"
>
Show Dialog
</button>
<dialog
role="alertdialog"
id="confirmation-dialog-content"
closedby="closerequest"
aria-labelledby="confirmation-dialog-title"
aria-describedby="confirmation-dialog-description"
size="default"
>
<header>
<h2 id="confirmation-dialog-title">Are you absolutely sure?</h2>
<p id="confirmation-dialog-description">
This action cannot be undone. This will permanently delete your
account from our servers.
</p>
</header>
<footer>
<button
type="button"
commandfor="confirmation-dialog-content"
command="close"
variant="outline"
>
Cancel
</button>
<button
type="button"
commandfor="confirmation-dialog-content"
command="close"
>
Continue
</button>
</footer>
</dialog>
</section>
</body>
</html>
Sizes And Composition
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Alert Dialog 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
ng-init="chatDeleted=false"
data-example="alert-dialog-destructive alert-dialog-media alert-dialog-rtl alert-dialog-small alert-dialog-small-media"
>
<main class="alert-dialog-workflows">
<div class="alert-dialog-trigger-grid" aria-label="Alert dialog examples">
<section id="share-project-dialog">
<button
type="button"
variant="outline"
commandfor="share-project-dialog-content"
command="show-modal"
>
Share Project
</button>
<dialog
role="alertdialog"
size="default"
id="share-project-dialog-content"
closedby="closerequest"
aria-labelledby="share-project-dialog-title"
aria-describedby="share-project-dialog-description"
>
<header>
<figure aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none">
<circle
cx="12"
cy="12"
r="9"
stroke="currentColor"
stroke-width="2"
/>
<path
d="M12 8v8M8 12h8"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</figure>
<h2 id="share-project-dialog-title">Share this project?</h2>
<p id="share-project-dialog-description">
Anyone with the link will be able to view and edit this project.
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="share-project-dialog-content"
command="close"
>
Cancel
</button>
<button
type="button"
commandfor="share-project-dialog-content"
command="close"
>
Share
</button>
</footer>
</dialog>
</section>
<section id="accessory-dialog">
<button
type="button"
variant="outline"
commandfor="accessory-dialog-content"
command="show-modal"
>
Show Small Dialog
</button>
<dialog
role="alertdialog"
size="sm"
id="accessory-dialog-content"
closedby="closerequest"
aria-labelledby="accessory-dialog-title"
aria-describedby="accessory-dialog-description"
>
<header>
<h2 id="accessory-dialog-title">Allow accessory to connect?</h2>
<p id="accessory-dialog-description">
Do you want to allow the USB accessory to connect to this
device?
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="accessory-dialog-content"
command="close"
>
Don't allow
</button>
<button
type="button"
commandfor="accessory-dialog-content"
command="close"
>
Allow
</button>
</footer>
</dialog>
</section>
<section id="accessory-media-dialog">
<button
type="button"
variant="outline"
commandfor="accessory-media-dialog-content"
command="show-modal"
>
Show Small Dialog With Media
</button>
<dialog
role="alertdialog"
size="sm"
id="accessory-media-dialog-content"
closedby="closerequest"
aria-labelledby="accessory-media-dialog-title"
aria-describedby="accessory-media-dialog-description"
>
<header>
<figure aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none">
<path
d="m7 7 10 10-5 5V2l5 5L7 17"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</figure>
<h2 id="accessory-media-dialog-title">
Allow accessory to connect?
</h2>
<p id="accessory-media-dialog-description">
Do you want to allow the USB accessory to connect to this
device?
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="accessory-media-dialog-content"
command="close"
>
Don't allow
</button>
<button
type="button"
commandfor="accessory-media-dialog-content"
command="close"
>
Allow
</button>
</footer>
</dialog>
</section>
<section id="delete-chat-dialog">
<button
type="button"
variant="destructive"
commandfor="delete-chat-dialog-content"
command="show-modal"
>
Delete Chat
</button>
<dialog
role="alertdialog"
size="sm"
id="delete-chat-dialog-content"
closedby="closerequest"
aria-labelledby="delete-chat-dialog-title"
aria-describedby="delete-chat-dialog-description"
>
<header>
<figure class="alert-dialog-media-destructive" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none">
<path
d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v5M14 11v5"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</figure>
<h2 id="delete-chat-dialog-title">Delete chat?</h2>
<p id="delete-chat-dialog-description">
This will permanently delete this chat conversation. View
<a href="#settings">Settings</a> to delete saved memories.
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="delete-chat-dialog-content"
command="close"
>
Cancel
</button>
<button
type="button"
variant="destructive"
ng-click="chatDeleted=true"
commandfor="delete-chat-dialog-content"
command="close"
>
Delete
</button>
</footer>
</dialog>
</section>
<div class="alert-dialog-rtl-triggers" dir="rtl" lang="ar">
<section id="rtl-confirmation-dialog">
<button
type="button"
variant="outline"
commandfor="rtl-confirmation-dialog-content"
command="show-modal"
>
إظهار الحوار
</button>
<dialog
role="alertdialog"
size="default"
id="rtl-confirmation-dialog-content"
closedby="closerequest"
aria-labelledby="rtl-confirmation-dialog-title"
aria-describedby="rtl-confirmation-dialog-description"
>
<header>
<h2 id="rtl-confirmation-dialog-title">هل أنت متأكد تمامًا؟</h2>
<p id="rtl-confirmation-dialog-description">
لا يمكن التراجع عن هذا الإجراء. سيؤدي هذا إلى حذف حسابك
نهائيًا من خوادمنا.
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="rtl-confirmation-dialog-content"
command="close"
>
إلغاء
</button>
<button
type="button"
commandfor="rtl-confirmation-dialog-content"
command="close"
>
متابعة
</button>
</footer>
</dialog>
</section>
<section id="rtl-accessory-dialog">
<button
type="button"
variant="outline"
commandfor="rtl-accessory-dialog-content"
command="show-modal"
>
إظهار الحوار (صغير)
</button>
<dialog
role="alertdialog"
size="sm"
id="rtl-accessory-dialog-content"
closedby="closerequest"
aria-labelledby="rtl-accessory-dialog-title"
aria-describedby="rtl-accessory-dialog-description"
>
<header>
<figure aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none">
<path
d="m7 7 10 10-5 5V2l5 5L7 17"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</figure>
<h2 id="rtl-accessory-dialog-title">السماح للملحق بالاتصال؟</h2>
<p id="rtl-accessory-dialog-description">
هل تريد السماح لملحق USB بالاتصال بهذا الجهاز؟
</p>
</header>
<footer>
<button
type="button"
variant="outline"
commandfor="rtl-accessory-dialog-content"
command="close"
>
عدم السماح
</button>
<button
type="button"
commandfor="rtl-accessory-dialog-content"
command="close"
>
السماح
</button>
</footer>
</dialog>
</section>
</div>
</div>
<output class="output">
Chat: {{ chatDeleted ? 'deleted' : 'available' }}
</output>
</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. A native dialog configured for decisions.
Anatomy
Root styling selector
dialog[role="alertdialog"]
Semantic structure
Use a native dialog with role="alertdialog" beside its invoker button. Close controls use command=close; semantic headers, figures, and footers need no anatomy classes or nested AngularCSS attributes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
role | Authored | Explicit semantic role when native HTML does not provide one. |
size | Authored | Compact action layout: sm; omit for the default dialog layout. |
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. Use closedby=closerequest when pointer light-dismiss must be disabled. AngularCSS registers no alert-dialog directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Connect the native dialog to a concise title and consequence description with aria-labelledby and aria-describedby. Put the least destructive action first in focus order and use closedby=closerequest when outside dismissal would be unsafe.
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.
2 - application-shell
Compose a persistent application header, the existing Sidebar, and a semantic
main workspace. Routing, permissions, and page content remain application-owned.
The reference uses the Sidebar’s responsive attribute so navigation starts
off-canvas on narrow screens without adding an application-specific class.
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 Application Shell</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="application-shell-demo">
<section class="application-shell">
<header>
<button
size="icon-sm"
variant="ghost"
aria-label="Toggle navigation"
aria-controls="enterprise-navigation"
>
☰
</button>
<a href="#workspace">Northstar Operations</a>
<menu>
<button size="sm" variant="outline">Help</button>
<button size="icon-sm" variant="ghost" aria-label="Account">
AL
</button>
</menu>
</header>
<aside
id="enterprise-navigation"
ng-sidebar
collapsible="offcanvas"
responsive
aria-label="Primary navigation"
>
<div>
<nav>
<section>
<h2>Workspace</h2>
<ul>
<li>
<a href="#overview" aria-current="page"
><span>Overview</span></a
>
</li>
<li>
<a href="#customers"><span>Customers</span></a>
</li>
<li>
<a href="#orders"><span>Orders</span></a>
</li>
</ul>
</section>
</nav>
</div>
</aside>
<main id="workspace">
<article class="card">
<header>
<h1>Operations overview</h1>
<p>Review current work and open exceptions.</p>
</header>
<section>All systems are operating normally.</section>
</article>
</main>
</section>
</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. Application header, navigation, and workspace composition.
Anatomy
Root styling selector
.application-shell
Semantic structure
Use one .application-shell containing a direct semantic header, an existing Sidebar, and a direct main landmark. Existing components keep their own root selectors; no shell part classes are required.
API
Attributes and state
This component has no directive-specific attributes beyond its semantic HTML.
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
Application Shell composes a semantic header, Sidebar, and main landmark. Routing, session state, permissions, responsive navigation policy, and page content remain application-owned.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Prefer semantic landmarks and native elements inside the layout. Any interactive handles or triggers must retain an accessible name and visible focus indicator.
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.
3 - data-table
Compose Table, Filter Bar, Pagination, and native controls around backend-owned rows. AngularCSS supplies the dense workspace presentation while AngularTS owns local bindings and the backend owns data operations.
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 Data Table</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="query=''; order='customer'; page=1; state={loading:false,error:false,stale:true,selected:false,canArchive:false}; rows=[{id:'ORD-1048',customer:'Ada Lovelace',status:'Open',total:'€1,240',selected:false},{id:'ORD-1047',customer:'Grace Hopper',status:'Review',total:'€860',selected:false},{id:'ORD-1046',customer:'Edsger Dijkstra',status:'Complete',total:'€420',selected:false},{id:'ORD-1045',customer:'Margaret Hamilton',status:'Open',total:'€2,100',selected:false}]"
data-example="data-table-demo"
>
<section
class="data-table visual-example"
aria-labelledby="orders-title"
aria-busy="{{ state.loading }}"
>
<header>
<div>
<h2 id="orders-title">Orders</h2>
<p>Recent customer orders</p>
</div>
<form role="search" aria-label="Filter orders">
<fieldset>
<legend class="visually-hidden">Filters</legend>
<label>
<span class="visually-hidden">Search orders</span>
<input
type="search"
ng-model="query"
placeholder="Search orders"
/>
</label>
</fieldset>
</form>
</header>
<aside
variant="warning"
aria-live="polite"
ng-if="state.stale && !state.loading && !state.error"
role="alert"
>
<h3>Showing cached orders</h3>
<p>The latest refresh did not complete. Values may be out of date.</p>
<button
size="xs"
variant="ghost"
type="button"
ng-click="state.stale=false"
>
Dismiss
</button>
</aside>
<aside
variant="destructive"
aria-live="assertive"
ng-if="state.error"
role="alert"
>
<h3>Orders could not be loaded</h3>
<p>The service returned an error. Existing filters are preserved.</p>
<button
size="xs"
variant="outline"
type="button"
ng-click="state.error=false; state.loading=true"
>
Retry
</button>
</aside>
<menu aria-label="Selected order actions" ng-if="state.selected">
<output>
<span ng-repeat="row in rows | filter:{selected:true}" ng-show="$last"
>{{ $index + 1 }}</span
>
selected
</output>
<button size="sm" variant="outline" type="button">Export</button>
<button
size="sm"
type="button"
ng-disabled="!state.canArchive"
aria-describedby="orders-permission-note"
>
Archive
</button>
</menu>
<figure>
<section class="empty" ng-if="state.loading" aria-live="polite">
<output class="spinner" aria-label="Loading orders"></output>
<h3>Loading orders</h3>
<p>Current filters and selection will be preserved.</p>
</section>
<table ng-if="!state.loading && !state.error">
<caption>
Orders currently available to your account.
</caption>
<thead>
<tr>
<th scope="col">
<input
type="checkbox"
aria-label="Select all orders"
ng-model="state.selectAll"
ng-change="rows[0].selected=state.selectAll; rows[1].selected=state.selectAll; rows[2].selected=state.selectAll; rows[3].selected=state.selectAll; state.selected=state.selectAll"
/>
</th>
<th scope="col">
<button
variant="ghost"
ng-click="order=order==='id' ? '-id' : 'id'"
>
Order
</button>
</th>
<th scope="col">
<button
variant="ghost"
ng-click="order=order==='customer' ? '-customer' : 'customer'"
>
Customer
</button>
</th>
<th scope="col">Status</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
<tr
ng-repeat="row in rows | filter:query | orderBy:order | limitTo:2:(page - 1) * 2"
aria-selected="{{ row.selected }}"
>
<td>
<input
type="checkbox"
aria-label="Select {{ row.id }}"
ng-model="row.selected"
ng-change="state.selected=rows[0].selected || rows[1].selected || rows[2].selected || rows[3].selected"
/>
</td>
<th scope="row">{{ row.id }}</th>
<td>{{ row.customer }}</td>
<td><span class="badge">{{ row.status }}</span></td>
<td>{{ row.total }}</td>
</tr>
</tbody>
</table>
<p ng-if="!state.loading && !state.error">No matching orders.</p>
</figure>
<footer>
<div>
<output
><span>0</span
><span ng-repeat="row in rows | filter:query" ng-show="$last"
>{{ $index + 1 }}</span
>
orders</output
>
<p id="orders-permission-note" ng-if="!state.canArchive">
Your role can export orders but cannot archive them.
</p>
</div>
<nav class="pagination" aria-label="Order pages">
<ul>
<li>
<a
href="#page-1"
ng-click="page=1"
aria-current="{{ page === 1 ? 'page' : 'false' }}"
>1</a
>
</li>
<li>
<a
href="#page-2"
ng-click="page=2"
aria-current="{{ page === 2 ? 'page' : 'false' }}"
>2</a
>
</li>
</ul>
</nav>
</footer>
</section>
</body>
</html>
Backend-driven states
The recipe keeps service state in authored HTML so applications can bind it to their own requests and authorization model:
| State | HTML contract |
|---|---|
| Loading | Set aria-busy="true" on .data-table and replace the table region with Spinner, Skeleton, or Progress content. |
| Empty | Keep a direct explanatory paragraph or compose Empty after the filtered tbody has no rows. |
| Error | Place an Alert with aria-live="assertive" before the data region and retain filters for retry. |
| Permission limited | Disable unavailable native actions and connect the reason with aria-describedby. |
| Stale data | Place a warning Alert with aria-live="polite" before the data region. |
| Filtering and paging | Bind Filter Bar controls and Pagination links to application-owned query and page state. |
| Selection and bulk action | Bind native checkboxes to row aria-selected and reveal one shared action menu when rows are selected. |
AngularCSS styles these compositions without defining a request, cache, authorization, or data-source API.
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. Semantic table with application-owned data operations.
Anatomy
Root styling selector
.data-table
Semantic structure
Use .data-table on a section containing a semantic header, a figure with a native table, and an optional footer. Compose Filter Bar, Pagination, Checkbox, Button, Badge, Empty, Skeleton, and Progress without data-table part classes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
aria-selected | Authored | Selected row state. |
aria-sort | Authored | Column sort state: ascending, descending, none, or other. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|---|
--data-table-max-height | Maximum scrollable table height; defaults to 32rem. |
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
Data Table composes the native Table, Filter Bar, Pagination, and existing controls. AngularTS or the backend owns rows, sorting, filtering, selection, pagination, loading, and mutations.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Keep native table, caption, header scope, and cell relationships. Sorting controls are buttons and expose direction with aria-sort; selection uses labeled native checkboxes and row aria-selected only when needed.
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.
4 - date-picker
Compose Calendar with the native Popover API and an application-owned date value. This recipe packages the existing date workflow without adding another model, parser, or form directive.
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 Date Picker</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="selectedDate='2026-09-05'"
data-example="date-picker-demo"
>
<div class="date-picker visual-example">
<label for="delivery-date">Delivery date</label>
<span>
<button
id="delivery-date"
type="button"
variant="outline"
popovertarget="delivery-date-calendar"
>
<span>{{ selectedDate ? selectedDate : 'Choose a date' }}</span
><span aria-hidden="true">▾</span>
</button>
<aside
id="delivery-date-calendar"
popover
side="bottom"
align="start"
aria-label="Choose delivery date"
>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ selectedDate }}"
ng-on-angularcss:calendar-select="selectedDate=$event.detail.value"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous month"
>
‹
</button>
<h2></h2>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next month"
>
›
</button>
</header>
<div></div>
</section>
</aside>
</span>
<p>The application owns parsing, validation, and the submitted value.</p>
</div>
</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. Calendar, popover, and form-control composition.
Anatomy
Root styling selector
.date-picker
Semantic structure
Use .date-picker around a visible label and the existing Popover and Calendar roots. The trigger may display an AngularTS-formatted value; no date-picker part classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
aria-invalid | Authored | Validation state on the Date Picker root, reflected on its trigger border. |
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
Date Picker composes Calendar with the native Popover API and a native form control or button. Calendar owns date-grid mechanics; AngularTS owns the model, parsing, validation, formatting, and submitted value.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Give the trigger and calendar useful names, preserve visible focus, and expose the selected date as text. The composed Calendar retains its full keyboard contract inside the native popover.
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.
5 - drawer
Drawers are native modal dialogs with CSS edge placement and optional handle, header, scroll body, and footer. AngularTS owns values and actions inside them.
<section class="drawer">
<button commandfor="goal-drawer" command="show-modal">Open Drawer</button>
<dialog id="goal-drawer" side="bottom">
<h2>Move Goal</h2>
<p>Set your daily activity goal.</p>
<button commandfor="goal-drawer" command="close">Cancel</button>
</dialog>
</section>
Activity Goal
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 Drawer</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="goal=350; submittedGoal=350"
data-example="drawer-demo"
>
<main class="visual-example">
<section id="goal-drawer" class="drawer">
<button
commandfor="goal-drawer-content"
command="show-modal"
variant="outline"
>
Open Drawer
</button>
<dialog
id="goal-drawer-content"
closedby="any"
aria-labelledby="goal-drawer-title"
aria-describedby="goal-drawer-description"
side="bottom"
>
<article>
<header>
<h2 id="goal-drawer-title">Move Goal</h2>
<p id="goal-drawer-description">Set your daily activity goal.</p>
</header>
<section>
<menu>
<button
variant="outline"
size="icon-sm"
aria-label="Decrease"
ng-disabled="goal <= 200"
ng-click="goal=goal-10"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14"></path>
</svg>
</button>
<output>
<strong ng-bind="goal"></strong>
<span>Calories/day</span>
</output>
<button
variant="outline"
size="icon-sm"
aria-label="Increase"
ng-disabled="goal>= 400"
ng-click="goal=goal+10"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M12 5v14"></path>
<path d="M5 12h14"></path>
</svg>
</button>
</menu>
<figure aria-hidden="true">
<span style="--height: 80%"></span
><span style="--height: 60%"></span>
<span style="--height: 40%"></span
><span style="--height: 60%"></span>
<span style="--height: 40%"></span
><span style="--height: 56%"></span>
<span style="--height: 38%"></span
><span style="--height: 48%"></span>
<span style="--height: 60%"></span
><span style="--height: 40%"></span>
<span style="--height: 56%"></span
><span style="--height: 38%"></span>
<span style="--height: 70%"></span>
</figure>
</section>
<footer>
<button
commandfor="goal-drawer-content"
command="close"
ng-click="submittedGoal=goal"
>
Submit
</button>
<button
commandfor="goal-drawer-content"
command="close"
variant="outline"
>
Cancel
</button>
</footer>
</article>
</dialog>
</section>
<output class="drawer-output" aria-live="polite">
Submitted goal: <span ng-bind="submittedGoal"></span>
</output>
</main>
</body>
</html>
Responsive Dialog
The application chooses Dialog on desktop and Drawer on compact viewports while sharing the same AngularTS form model.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Drawer 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={email:'team@angularcss.dev',username:'@angularcss'}"
data-example="drawer-dialog"
>
<main class="drawer-dialog-demo visual-example">
<div class="drawer-dialog-desktop">
<section id="responsive-profile-dialog" class="dialog">
<button
variant="outline"
type="button"
commandfor="responsive-profile-dialog-content"
command="show-modal"
>
Edit Profile
</button>
<dialog
class="drawer-profile-dialog"
id="responsive-profile-dialog-content"
closedby="any"
aria-labelledby="responsive-profile-dialog-title"
aria-describedby="responsive-profile-dialog-description"
>
<header>
<h2 id="responsive-profile-dialog-title">Edit profile</h2>
<p id="responsive-profile-dialog-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<form class="drawer-profile-form">
<div class="drawer-profile-field">
<label for="desktop-email">Email</label>
<input
id="desktop-email"
type="email"
ng-model="profile.email"
/>
</div>
<div class="drawer-profile-field">
<label for="desktop-username">Username</label>
<input id="desktop-username" ng-model="profile.username" />
</div>
<button
type="button"
commandfor="responsive-profile-dialog-content"
command="close"
>
Save changes
</button>
</form>
</dialog>
</section>
</div>
<div class="drawer-dialog-mobile">
<section id="responsive-profile-drawer" class="drawer">
<button
variant="outline"
type="button"
commandfor="responsive-profile-drawer-content"
command="show-modal"
>
Edit Profile
</button>
<dialog
id="responsive-profile-drawer-content"
closedby="any"
aria-labelledby="responsive-profile-drawer-title"
aria-describedby="responsive-profile-drawer-description"
side="bottom"
>
<header>
<h2 id="responsive-profile-drawer-title">Edit profile</h2>
<p id="responsive-profile-drawer-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<form class="drawer-profile-form drawer-profile-mobile">
<div class="drawer-profile-field">
<label for="mobile-email">Email</label>
<input
id="mobile-email"
type="email"
ng-model="profile.email"
/>
</div>
<div class="drawer-profile-field">
<label for="mobile-username">Username</label>
<input id="mobile-username" ng-model="profile.username" />
</div>
<button
type="button"
commandfor="responsive-profile-drawer-content"
command="close"
>
Save changes
</button>
</form>
<footer>
<button
variant="outline"
commandfor="responsive-profile-drawer-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
</div>
</main>
</body>
</html>
Sides
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Drawer Sides</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="paragraphs=[1,2,3,4,5,6,7,8,9,10]"
data-example="drawer-sides"
>
<main class="drawer-sides-demo visual-example">
<section side="top" class="drawer">
<button
variant="outline"
type="button"
commandfor="drawer-native-627-content"
command="show-modal"
>
Top
</button>
<dialog
size="half"
id="drawer-native-627-content"
closedby="any"
aria-labelledby="drawer-native-627-title"
aria-describedby="drawer-native-627-description"
side="top"
>
<header>
<h2 id="drawer-native-627-title">Top drawer</h2>
<p id="drawer-native-627-description">
Review activity from the top edge.
</p>
</header>
<section class="drawer-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button
variant="outline"
commandfor="drawer-native-627-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="right" class="drawer">
<button
variant="outline"
type="button"
commandfor="drawer-native-1891-content"
command="show-modal"
>
Right
</button>
<dialog
id="drawer-native-1891-content"
closedby="any"
aria-labelledby="drawer-native-1891-title"
aria-describedby="drawer-native-1891-description"
side="right"
>
<header>
<h2 id="drawer-native-1891-title">Right drawer</h2>
<p id="drawer-native-1891-description">
Review activity from the right edge.
</p>
</header>
<section class="drawer-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button
variant="outline"
commandfor="drawer-native-1891-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="bottom" class="drawer">
<button
variant="outline"
type="button"
commandfor="drawer-native-3155-content"
command="show-modal"
>
Bottom
</button>
<dialog
size="half"
id="drawer-native-3155-content"
closedby="any"
aria-labelledby="drawer-native-3155-title"
aria-describedby="drawer-native-3155-description"
side="bottom"
>
<header>
<h2 id="drawer-native-3155-title">Bottom drawer</h2>
<p id="drawer-native-3155-description">
Review activity from the bottom edge.
</p>
</header>
<section class="drawer-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button
variant="outline"
commandfor="drawer-native-3155-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="left" class="drawer">
<button
variant="outline"
type="button"
commandfor="drawer-native-4485-content"
command="show-modal"
>
Left
</button>
<dialog
id="drawer-native-4485-content"
closedby="any"
aria-labelledby="drawer-native-4485-title"
aria-describedby="drawer-native-4485-description"
side="left"
>
<header>
<h2 id="drawer-native-4485-title">Left drawer</h2>
<p id="drawer-native-4485-description">
Review activity from the left edge.
</p>
</header>
<section class="drawer-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button
variant="outline"
commandfor="drawer-native-4485-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
</main>
</body>
</html>
Scrollable Content
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Drawer Scrollable</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="paragraphs=[1,2,3,4,5,6,7,8,9,10]"
data-example="drawer-scrollable-content"
>
<main class="drawer-scroll-demo visual-example">
<section id="scrollable-drawer" side="right" class="drawer">
<button
variant="outline"
type="button"
commandfor="scrollable-drawer-content"
command="show-modal"
>
Scrollable Content
</button>
<dialog
id="scrollable-drawer-content"
closedby="any"
aria-labelledby="scrollable-drawer-title"
aria-describedby="scrollable-drawer-description"
side="right"
>
<header>
<h2 id="scrollable-drawer-title">Move Goal</h2>
<p id="scrollable-drawer-description">
Set your daily activity goal.
</p>
</header>
<section class="drawer-scroll-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button>Submit</button>
<button
variant="outline"
commandfor="scrollable-drawer-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</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 Drawer 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="goal=350"
data-example="drawer-rtl"
>
<main class="visual-example">
<section id="rtl-goal-drawer" class="drawer">
<button
variant="outline"
type="button"
commandfor="rtl-goal-drawer-content"
command="show-modal"
>
فتح الدرج
</button>
<dialog
id="rtl-goal-drawer-content"
closedby="any"
aria-labelledby="rtl-goal-drawer-title"
aria-describedby="rtl-goal-drawer-description"
side="bottom"
>
<article>
<header>
<h2 id="rtl-goal-drawer-title">نقل الهدف</h2>
<p id="rtl-goal-drawer-description">حدد هدف نشاطك اليومي.</p>
</header>
<section>
<menu>
<button
variant="outline"
size="icon-sm"
aria-label="تقليل"
ng-click="goal=goal-10"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14"></path>
</svg>
</button>
<output>
<strong ng-bind="goal"></strong>
<span>سعرات حرارية/يوم</span>
</output>
<button
variant="outline"
size="icon-sm"
aria-label="زيادة"
ng-click="goal=goal+10"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M12 5v14"></path>
<path d="M5 12h14"></path>
</svg>
</button>
</menu>
<figure aria-hidden="true">
<span style="--height: 80%"></span
><span style="--height: 60%"></span>
<span style="--height: 40%"></span
><span style="--height: 60%"></span>
<span style="--height: 40%"></span
><span style="--height: 56%"></span>
<span style="--height: 38%"></span
><span style="--height: 48%"></span>
<span style="--height: 60%"></span
><span style="--height: 40%"></span>
<span style="--height: 56%"></span
><span style="--height: 38%"></span>
<span style="--height: 70%"></span>
</figure>
</section>
<footer>
<button>إرسال</button>
<button
variant="outline"
commandfor="rtl-goal-drawer-content"
command="close"
>
إلغاء
</button>
</footer>
</article>
</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. A native dialog placed at a viewport edge.
Anatomy
Root styling selector
.drawer
Semantic structure
Use .drawer as a wrapper containing a native invoker button and dialog with authored side. Close controls use command=close; the bottom handle is generated by CSS and no anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
dir | Authored | Text and interaction direction: ltr or rtl. |
side | Authored | Dialog edge: top, right, bottom, or left. |
size | Authored | Use half for a half-height top or bottom drawer. |
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 owns modal disclosure, focus, Escape, background isolation, and restoration. The concise authored side attribute selects CSS edge placement. AngularTS remains responsible for form models, goal values, validation, submission, responsive application composition, and authored content.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Use a visible title and description connected to the native dialog. Keep the physical edge as presentation only; content order, focus order, and inherited text direction remain semantic.
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.
6 - form-layout
Arrange native fieldsets and existing Field patterns into responsive columns. Native validation and AngularTS forms remain the authoritative form model.
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 Form Layout</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="form-layout-demo">
<form
class="form-layout visual-example"
name="customerForm"
novalidate
ng-submit="saved=customerForm.valid"
>
<header>
<h2>Create customer</h2>
<p>Fields marked as required must be completed.</p>
</header>
<aside
role="alert"
ng-if="customerForm.submitted && customerForm.invalid"
>
<header><h3>Check the customer details</h3></header>
<ul>
<li><a href="#form-layout-name">Enter a customer name.</a></li>
</ul>
</aside>
<fieldset>
<legend>Customer details</legend>
<div class="field">
<label for="form-layout-name">Customer name</label>
<input
id="form-layout-name"
name="customerName"
required
ng-model="customer.name"
/>
</div>
<div class="field">
<label for="form-layout-email">Email</label>
<input
id="form-layout-email"
type="email"
name="email"
ng-model="customer.email"
/>
</div>
<div class="field">
<label for="form-layout-region">Region</label>
<select
id="form-layout-region"
name="region"
ng-model="customer.region"
>
<option value="">Choose a region</option>
<option>Europe</option>
<option>Americas</option>
</select>
</div>
<div class="field">
<label for="form-layout-reference">Reference</label>
<input
id="form-layout-reference"
name="reference"
ng-model="customer.reference"
/>
</div>
</fieldset>
<footer>
<button variant="outline" type="reset">Cancel</button>
<button type="submit">Create customer</button>
</footer>
<output aria-live="polite" ng-if="saved"
>Customer is ready to save.</output
>
</form>
</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. Responsive native form and field composition.
Anatomy
Root styling selector
form.form-layout
Semantic structure
Apply .form-layout to a native form containing semantic headers, fieldsets, Field patterns, an optional Validation Summary, and a footer. No form-layout part classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
columns | Authored | Preferred desktop column count: 1, 2, or 3. |
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
Form Layout arranges native fieldsets and Field patterns. Native validation and AngularTS forms remain authoritative for values, errors, submission, and server responses.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Preserve DOM and focus order as the layout changes columns. Group related controls with fieldset and legend, connect errors to controls, and place a Validation Summary before invalid fields.
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.
7 - master-detail
Compose Resizable with semantic navigation and an article to browse records without losing context. AngularTS or routing owns the selected record and data.
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 Master Detail</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="master-detail-demo">
<main
class="master-detail visual-example"
ng-resizable-panel-group
aria-label="Customer workspace"
>
<section style="--panel-size: 0.75">
<nav aria-label="Customers">
<header><h2>Customers</h2></header>
<ul>
<li>
<a href="#ada" aria-current="page"
><strong>Ada Lovelace</strong
><small>Enterprise · Active</small></a
>
</li>
<li>
<a href="#grace"
><strong>Grace Hopper</strong
><small>Business · Review</small></a
>
</li>
<li>
<a href="#edsger"
><strong>Edsger Dijkstra</strong
><small>Enterprise · Active</small></a
>
</li>
</ul>
</nav>
</section>
<hr aria-label="Resize customer list" />
<section style="--panel-size: 2">
<article id="ada">
<header>
<h1>Ada Lovelace</h1>
<p>Enterprise customer since 2024</p>
</header>
<section>
<dl>
<div>
<dt>Email</dt>
<dd>ada@example.com</dd>
</div>
<div>
<dt>Region</dt>
<dd>Europe</dd>
</div>
<div>
<dt>Status</dt>
<dd>Active</dd>
</div>
</dl>
</section>
</article>
</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. Responsive record list and detail workspace.
Anatomy
Root styling selector
.master-detail
Semantic structure
Apply .master-detail and ng-resizable-panel-group to the same root. Use two direct sections separated by a labeled hr; place semantic navigation in the first and record content in the second.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
orientation | Authored | Resizable panel axis: horizontal or vertical; the recipe stacks on narrow viewports. |
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
Master–Detail composes Resizable with semantic navigation and record content. The application owns record selection, routing, data loading, responsive overlay policy, and persistence of panel sizes.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Use a labeled navigation landmark for the master list and a semantic article for detail content. Resizable handles retain separator semantics, while narrow layouts preserve the same reading order.
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.
8 - sheet
Use a native dialog and declarative invoker. Author side on the dialog as
right, left, top, or bottom; CSS owns only physical placement.
<section class="sheet">
<button commandfor="profile-sheet" command="show-modal">Open</button>
<dialog id="profile-sheet" side="right">
<header>
<h2>Edit profile</h2>
<p>Update your account details.</p>
</header>
<section>Content</section>
<footer>
<button commandfor="profile-sheet" command="close">Close</button>
</footer>
</dialog>
</section>
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 Sheet</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="sheet-demo"
>
<main class="visual-example">
<section id="profile-sheet" class="sheet">
<button
commandfor="profile-sheet-content"
command="show-modal"
variant="outline"
>
Open
</button>
<dialog
id="profile-sheet-content"
closedby="any"
aria-labelledby="profile-sheet-title"
aria-describedby="profile-sheet-description"
side="right"
>
<header>
<h2 id="profile-sheet-title">Edit profile</h2>
<p id="profile-sheet-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<form method="dialog">
<section>
<label
><span>Name</span>
<input id="sheet-demo-name" ng-model="profile.name" autofocus />
</label>
<label
><span>Username</span>
<input id="sheet-demo-username" ng-model="profile.username" />
</label>
</section>
<footer>
<button
type="button"
commandfor="profile-sheet-content"
command="close"
ng-click="savedName=profile.name"
>
Save changes
</button>
<button
type="button"
commandfor="profile-sheet-content"
command="close"
variant="outline"
>
Close
</button>
</footer>
</form>
<button
type="button"
commandfor="profile-sheet-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 sheet</span>
</button>
</dialog>
</section>
<output class="sheet-output" aria-live="polite">
Saved profile: <span ng-bind="savedName"></span>
</output>
</main>
</body>
</html>
The example keeps profile values and save state in AngularTS. Sheet owns only modal disclosure, semantics, focus, and placement.
Without Corner Close
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sheet No Close</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="sheet-no-close-button">
<main class="visual-example">
<section id="plain-sheet" class="sheet">
<button
variant="outline"
type="button"
commandfor="plain-sheet-content"
command="show-modal"
>
Open Sheet
</button>
<dialog
id="plain-sheet-content"
closedby="any"
aria-labelledby="plain-sheet-title"
aria-describedby="plain-sheet-description"
side="right"
>
<header>
<h2 id="plain-sheet-title">No Close Button</h2>
<p id="plain-sheet-description">
This sheet doesn't have a close button in the top-right corner.
Click outside to close.
</p>
</header>
</dialog>
</section>
</main>
</body>
</html>
The panel intentionally omits close controls and remains dismissible through the exact overlay or Escape.
Sides
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sheet Sides</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="paragraphs=[1,2,3,4,5,6,7,8,9,10]"
data-example="sheet-side"
>
<main class="sheet-sides-demo visual-example">
<section side="top" class="sheet">
<button
variant="outline"
type="button"
commandfor="sheet-native-624-content"
command="show-modal"
>
Top
</button>
<dialog
size="half"
id="sheet-native-624-content"
closedby="any"
aria-labelledby="sheet-native-624-title"
aria-describedby="sheet-native-624-description"
side="top"
>
<header>
<h2 id="sheet-native-624-title">Edit profile</h2>
<p id="sheet-native-624-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<section class="sheet-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button>Save changes</button>
<button
variant="outline"
commandfor="sheet-native-624-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="right" class="sheet">
<button
variant="outline"
type="button"
commandfor="sheet-native-1974-content"
command="show-modal"
>
Right
</button>
<dialog
id="sheet-native-1974-content"
closedby="any"
aria-labelledby="sheet-native-1974-title"
aria-describedby="sheet-native-1974-description"
side="right"
>
<header>
<h2 id="sheet-native-1974-title">Edit profile</h2>
<p id="sheet-native-1974-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<section class="sheet-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button>Save changes</button>
<button
variant="outline"
commandfor="sheet-native-1974-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="bottom" class="sheet">
<button
variant="outline"
type="button"
commandfor="sheet-native-3320-content"
command="show-modal"
>
Bottom
</button>
<dialog
size="half"
id="sheet-native-3320-content"
closedby="any"
aria-labelledby="sheet-native-3320-title"
aria-describedby="sheet-native-3320-description"
side="bottom"
>
<header>
<h2 id="sheet-native-3320-title">Edit profile</h2>
<p id="sheet-native-3320-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<section class="sheet-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button>Save changes</button>
<button
variant="outline"
commandfor="sheet-native-3320-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
<section side="left" class="sheet">
<button
variant="outline"
type="button"
commandfor="sheet-native-4686-content"
command="show-modal"
>
Left
</button>
<dialog
id="sheet-native-4686-content"
closedby="any"
aria-labelledby="sheet-native-4686-title"
aria-describedby="sheet-native-4686-description"
side="left"
>
<header>
<h2 id="sheet-native-4686-title">Edit profile</h2>
<p id="sheet-native-4686-description">
Make changes to your profile here. Click save when you're done.
</p>
</header>
<section class="sheet-side-copy">
<p ng-repeat="item in paragraphs">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris.
</p>
</section>
<footer>
<button>Save changes</button>
<button
variant="outline"
commandfor="sheet-native-4686-content"
command="close"
>
Cancel
</button>
</footer>
</dialog>
</section>
</main>
</body>
</html>
Top and bottom panels use a half-viewport maximum in this composition. The scrolling body remains independent from the header and footer.
RTL
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 Sheet 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:'Pedro Duarte',username:'peduarte'}; savedName='Pedro Duarte'"
data-example="sheet-rtl"
>
<main class="visual-example">
<section id="rtl-profile-sheet" side="left" class="sheet">
<button
variant="outline"
type="button"
commandfor="rtl-profile-sheet-content"
command="show-modal"
>
فتح
</button>
<dialog
id="rtl-profile-sheet-content"
closedby="any"
aria-labelledby="rtl-profile-sheet-title"
aria-describedby="rtl-profile-sheet-description"
side="left"
>
<header>
<h2 id="rtl-profile-sheet-title">تعديل الملف الشخصي</h2>
<p id="rtl-profile-sheet-description">
قم بإجراء تغييرات على ملفك الشخصي هنا. انقر حفظ عند الانتهاء.
</p>
</header>
<form method="dialog">
<section>
<label
><span>الاسم</span>
<input id="sheet-rtl-name" ng-model="profile.name" autofocus />
</label>
<label
><span>اسم المستخدم</span>
<input id="sheet-rtl-username" ng-model="profile.username" />
</label>
</section>
<footer>
<button
type="button"
ng-click="savedName=profile.name"
commandfor="rtl-profile-sheet-content"
command="close"
>
حفظ التغييرات
</button>
<button
type="button"
variant="outline"
commandfor="rtl-profile-sheet-content"
command="close"
>
إغلاق
</button>
</footer>
</form>
<button
variant="ghost"
size="icon-sm"
commandfor="rtl-profile-sheet-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>
<output class="sheet-output" aria-live="polite">
الملف المحفوظ: <span ng-bind="savedName"></span>
</output>
</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. A native dialog presented as a side sheet.
Anatomy
Root styling selector
.sheet
Semantic structure
Use .sheet as a wrapper containing a native invoker button and dialog with authored side. Close controls use command=close; semantic headers, sections, forms, and footers need no anatomy classes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
command | Authored | Native invoker action such as show-modal or close. |
dir | Authored | Text and interaction direction: ltr or rtl. |
side | Authored | Dialog edge: top, right, bottom, or left. |
size | Authored | Use half for a half-height top or bottom sheet. |
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 owns modal disclosure, focus, Escape, background isolation, and restoration. The concise authored side attribute selects CSS edge placement. AngularTS remains responsible for form values, validation, submission, language, and authored content.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Use a visible title and description connected to the native dialog. Keep the physical edge as presentation only; content order, focus order, and inherited text direction remain semantic.
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.