Documentation
Learn AngularCSS from installation through production component composition.
AngularCSS is a library of semantic HTML contracts, TypeScript directives, and
customizable CSS for AngularTS applications. These docs assume that you know
basic HTML but do not assume prior AngularCSS experience.
Start here
- Introduction explains what
AngularCSS owns and what remains native HTML or AngularTS behavior.
- Installation adds the
local npm packages, stylesheet, and
angular.css module. - Build your first component creates an interactive accordion.
- Customization covers
tokens, parts, and state selectors.
Browse the catalog
The catalog is organized by responsibility: foundations, elements,
patterns, components, and recipes. Every
entry has one canonical source, one functional demo, and one documentation page.
Production guides
- AngularTS ownership explains where models, validation,
bindings, and structural state belong.
- Composition combines primitives
into forms, menus, date pickers, and overlays.
- Accessibility covers authored
names, keyboard testing, focus, and generated ARIA state.
- Testing validates components and
documentation in a browser.
1 - Get Started
Install AngularCSS, understand its HTML-first model, and build a first component.
Follow these pages in order:
- Introduction
- Installation
- First component
- Customization
- Compatibility and upgrades
AngularCSS requires AngularTS. A package manager and build tool are recommended
for applications; the documentation website itself serves only locally bundled
assets and does not depend on a CDN.
1.1 - Introduction
Understand AngularCSS as semantic HTML, focused TypeScript behavior, and customizable CSS.
AngularCSS provides HTML-first styles and focused interface components for
AngularTS. Most interface elements are semantic HTML styled directly by CSS.
TypeScript components are reserved for interactions that native HTML, CSS, and
AngularTS do not already provide.
AngularCSS is a customization system, not a design system. It provides a stable
functional baseline and presentation controls; the application owns its brand,
visual language, and product-specific design.
<button variant="outline">Save changes</button>
No directive runs for this button. The browser owns activation and disabled
state, AngularTS owns application commands, and CSS targets the native element
and authored variant directly.
Three layers
- HTML owns semantics. Use
button, input, dialog, nav, table, and
other native elements whenever they fit the interaction. - AngularTS owns application state. Use
ng-model, ng-click, validation,
interpolation, and structural directives for values and business behavior. - AngularCSS fills genuine interaction gaps. Components add composite
keyboard navigation, focus management, disclosure coordination, and dynamic
accessibility relationships only when the first two layers are insufficient.
This boundary prevents a component from creating a second form model, template
engine, validation system, or styling-state mirror over AngularTS and the
browser.
HTML-first composition
Complex components are composed from named parts rather than hidden templates:
<details class="disclosure">
<summary>Account settings</summary>
<section>
<label for="display-name">Display name</label>
<input id="display-name" ng-model="profile.name" />
</section>
</details>
You control the elements, content, AngularTS expressions, and application CSS.
Each catalog page documents the authored HTML and any runtime behavior it needs.
What is included
- 67 documented entries split into foundations, elements, patterns, focused
behavioral components, and recipes.
- TypeScript declarations generated from the canonical source.
- A compiled CSS entrypoint and a DTCG 2025.10 customization token resolver.
- Local UMD and ESM builds.
- Browser-tested demos isolated from the documentation shell in iframes.
Next step
Install AngularCSS and
connect the angular.css module to an AngularTS application.
1.2 - Install AngularCSS
Install AngularTS and AngularCSS locally, load the stylesheet, and connect the ui module.
AngularCSS is distributed as an npm package. Its behavioral components require
AngularTS. Install both packages locally:
npm install @angular-wave/angular.ts @angular-wave/angular.css
No CDN is required. The package includes ESM, UMD, CSS, and TypeScript
declaration outputs.
Stylesheet-only setup
Native elements, patterns, foundations, and recipes need only the compiled
AngularCSS stylesheet:
@import "@angular-wave/angular.css/dist/angular.css";
<button variant="outline">Save</button>
These entries register no AngularCSS directive. Add AngularTS for application
bindings, and load AngularCSS JavaScript with the angular.css dependency when
using behavioral components such as tabs or comboboxes.
Bundler setup
Import AngularTS before AngularCSS so the runtime exists when AngularCSS
registers its directives. Import the compiled stylesheet once in your
application entrypoint:
import { angular } from "@angular-wave/angular.ts";
import "@angular-wave/angular.css";
import "@angular-wave/angular.css/dist/angular.css";
angular.createModule("app", ["angular.css"]);
Then attach your application module to an HTML root:
<main ng-app="app">
<button>Save</button>
</main>
The package registers one AngularTS module named angular.css. Your application
should depend on that module; do not register individual AngularCSS directives
again.
Local script setup
Applications without a bundler can copy the two UMD files and the compiled CSS
into their own static asset directory. Serve all three from the same origin:
<link rel="stylesheet" href="/vendor/angularcss/angular.css" />
<script src="/vendor/angular/angular-ts.umd.js"></script>
<script src="/vendor/angularcss/angular-css.umd.js"></script>
<div ng-app="angular.css">
<button>Save</button>
</div>
Load AngularTS first. The documentation examples use this local script order and
never fetch runtime code or styles from a CDN.
Application styles
Load AngularCSS before application styles so your custom properties and rules
can configure its defaults:
@import "@angular-wave/angular.css/dist/angular.css";
@layer components {
:root {
--primary: #175cd3;
--radius: 0.375rem;
}
button[variant="outline"] {
border-color: var(--border);
background: transparent;
}
}
The published CSS is compiled and has no framework dependency. See
Customization for the
complete CSS-variable and DTCG token contract.
Verify the installation
Render a button and inspect it in browser developer tools:
<button variant="secondary">Installed</button>
The element should retain its native attributes. If it remains unstyled, verify
the CSS import. Behavioral components additionally require the AngularTS script
order and the angular.css module dependency.
TypeScript
The package ships declarations under @types. TypeScript resolves them from the
package’s types field; no separate DefinitelyTyped package is needed.
Next step
Build your first component with semantic HTML and AngularTS state.
1.3 - Build Your First Component
Build an interactive accordion and connect ordinary AngularTS state inside it.
This page builds an accordion with native details and summary. The browser
owns disclosure; AngularTS owns the application value inside the panel.
Add the HTML
<section ng-app="app">
<section aria-label="Profile sections">
<details name="profile-sections" open>
<summary>Profile</summary>
<div>
<label for="display-name">Display name</label>
<input id="display-name" ng-model="profile.name" />
<output>Preview: {{ profile.name || "Unnamed" }}</output>
</div>
</details>
</section>
</section>
Each direct child is a native disclosure item. The browser creates the trigger
relationship and owns open state, focus, and keyboard activation.
Create the application module
import { angular } from "@angular-wave/angular.ts";
import "@angular-wave/angular.css";
import "@angular-wave/angular.css/dist/angular.css";
angular.createModule("app", ["angular.css"]);
No controller is required for this example. ng-model creates the profile name
binding in the application scope, and interpolation updates the preview.
AngularCSS does not parse or store that value.
Test the result
- Press Tab until the accordion trigger receives focus.
- Press Enter or Space to open and close the panel.
- Enter a display name and confirm the preview updates.
- Inspect the
details element’s native open state.
Add multiple panels
Add another sibling details with the same name to make the group exclusive.
Omit name when several panels may remain open:
<section aria-label="Sections">
<details>...</details>
<details>...</details>
</section>
Next step
Customize components, then browse the complete accordion
reference.
1.4 - Customization
Configure AngularCSS colors, spacing, typography, shadows, radii, density, focus, and motion with ordinary CSS or DTCG-compatible tools.
AngularCSS is a customization system, not a design system. It supplies a
consistent functional baseline and stable presentation controls. Your
application still decides its brand, visual language, content hierarchy, and
product-specific composition.
Every browser-facing customization control is a CSS custom property. Consumers
do not need a token compiler, Tailwind, Sass, JavaScript, or an AngularCSS build
step to change the defaults.
Load order
Load AngularCSS before application styles. The bundle declares this low-to-high
layer order: base, angularcss.tokens, angularcss.components, components,
and utilities.
@import "@angular-wave/angular.css/angular.css";
@layer components {
:root {
--primary: #175cd3;
--primary-foreground: #fff;
--radius: 0.375rem;
}
}
Unlayered application rules remain above normal layered declarations. Use the
public components layer for reusable application rules and utilities for
local exceptions.
AngularCSS authors its defaults as Design Tokens Community Group 2025.10 token
files. The package exports the resolver at
@angular-wave/angular.css/customization-tokens for design, documentation, and
translation tools.
The generated CSS variables remain the runtime API. The DTCG files improve
interoperability and validation; they do not turn AngularCSS into a design
system or require applications to adopt a token tool.
The customization families are:
- Colors: semantic surfaces, content, actions, states, charts, sidebar, and
compatibility palettes.
- Spacing: the base rhythm and an explicit spacing scale.
- Typography: font families, sizes, weights, and line heights.
- Shadows: elevation values for controls, panels, menus, and dialogs.
- Radii: control, surface, overlay, and fully rounded geometry.
- Sizing: control heights, icon sizes, and the minimum comfortable pointer
target.
- Borders and focus: shared widths and visible keyboard-focus geometry.
- Motion: shared durations and easing curves.
Global customization
Set semantic variables on :root to configure the entire application:
:root {
--background: #fff;
--foreground: #17202a;
--primary: #175cd3;
--primary-foreground: #fff;
--border: #d0d5dd;
--input: #98a2b3;
--ring: #528bff;
--spacing: 0.25rem;
--font-sans: Inter, system-ui, sans-serif;
--text-sm: 0.875rem;
--font-weight-medium: 500;
--shadow-md: 0 4px 8px rgb(16 24 40 / 12%);
--radius: 0.375rem;
}
Components consume semantic variables such as --background, --primary, and
--border. Palette variables such as --blue-9 remain available when an
application needs a concrete value, but component rules do not require a
specific brand palette.
Scoped customization
Custom properties inherit, so an application region can use different
presentation settings without copying component selectors:
.operations-console {
--spacing: 0.2rem;
--radius: 0.25rem;
--size-control-md: 2rem;
--shadow-md: 0 2px 5px rgb(16 24 40 / 10%);
}
Use scoped values for embedded tools, dense administrative areas, or gradual
brand migrations. Keep focus indicators and pointer targets usable when reducing
density.
Density contexts
Set data-density on the application root or a subtree to apply a coordinated
spacing and control-geometry preset. The attribute changes the same public
variables that applications can set directly.
<section data-density="compact">
<!-- Dense administrative workspace -->
</section>
compact favors information-dense pointer workflows. comfortable increases
spacing and target sizes for lower-density forms and touch-oriented areas. The
default context remains between the two. Applications can override any mapped
variable after the preset.
Contrast contexts
AngularCSS responds to prefers-contrast: more by strengthening borders,
control outlines, and focus rings. Use data-contrast="more" to request the
same treatment for a subtree independent of the operating-system preference:
<main data-contrast="more">...</main>
The context maps semantic variables and therefore follows customized light and
dark colors instead of imposing a separate palette.
Print contexts
Print styles remove shadows and motion, preserve readable light surfaces, and
let scrollable tables and data regions expand. Mark application-only controls
with data-print="exclude"; mark print-only content with data-print="only".
<button data-print="exclude">Edit</button>
<p data-print="only">Generated from the current customer record.</p>
These attributes express document intent in HTML and work across components.
Dark contexts
Add dark to any ancestor. AngularCSS provides dark defaults for the same
semantic variables:
<section class="dark">
<button>Continue</button>
</section>
Override variables inside the same selector to supply an application-specific
dark presentation:
.dark {
--background: #101828;
--foreground: #f2f4f7;
--primary: #84adff;
--primary-foreground: #102a56;
}
Selectors, parts, and state
Use documented root selectors, semantic descendants, native state, and
documented component state for customization beyond the shared variables:
.dialog > dialog {
max-width: 48rem;
}
[ng-tabs] > menu > button[aria-selected="true"] {
border-color: var(--primary);
}
Styling-only entries keep state in native selectors such as :checked,
:disabled, and :open. Behavioral components expose authored attributes, ARIA
state, and documented data-* state. Avoid selectors based on generated IDs or
child positions.
AngularCSS has no Tailwind dependency. Tailwind, Sass, CSS Modules, and other
application toolchains can set the same custom properties or add rules in the
public cascade layers. They do not need an AngularCSS-specific customization
model.
Preserve behavior
Customization may change spacing, color, typography, borders, geometry, shadows,
and motion. Keep focused elements visible, preserve keyboard focus, retain
usable contrast and pointer targets, and keep visual order aligned with DOM
order.
Use the component catalog to find each
component’s selectors, states, custom properties, and live source.
1.5 - Compatibility and upgrades
Understand AngularTS, browser, and Node.js compatibility and upgrade an AngularCSS application deliberately.
AngularCSS declares @angular-wave/angular.ts with the npm latest tag and
tests the registry’s current release in CI. A daily compatibility run catches a
new AngularTS release even when AngularCSS source has not changed. The package
lock still records the exact version used for a reproducible AngularCSS build.
Supported environments
- Current Chromium, Firefox, and WebKit engines are required browser projects.
- Node.js 24 or newer is required for development, documentation, and package
builds.
- The distributed CSS and browser JavaScript are prebuilt. Consumers do not need
the AngularCSS build toolchain.
- Behavioral components require AngularTS. Styling-only foundations, elements,
patterns, and recipes can use the compiled stylesheet alone.
AngularCSS uses current platform features including native dialog, the Popover
API, CSS custom properties, cascade layers, logical properties, :has(), and
@scope. Test the final application against its own supported browser policy,
content, localization, zoom, and assistive technology.
Upgrade both packages
Resolve both current releases together and review the lockfile:
npm install @angular-wave/angular.ts@latest @angular-wave/angular.css@latest
npm run build
Then run the application’s keyboard, form, overlay, narrow viewport, and data
workflow tests. Review the AngularCSS changelog for selector, attribute, event,
or custom-property changes. Versions below 0.1.0 may refine public contracts
while the catalog is being stabilized.
Upgrading from 0.0.1 to 0.0.2
The core package no longer uses Tailwind in its source, build, or distribution.
Continue importing the same compiled CSS entrypoint. Customize semantic CSS
variables directly; Tailwind applications can set those variables from their own
stylesheet without an AngularCSS adapter.
0.0.2 adds DTCG 2025.10 token files, density and contrast contexts, print
attributes, broader enterprise-state recipes, and stricter accessible HTML.
Re-test any application CSS that depended on undocumented generated selectors or
Tailwind implementation variables.
Diagnose a compatibility failure
Run the same policy check used by CI:
npm install --no-save --package-lock=false @angular-wave/angular.ts@latest
npm run check:angular-ts-version -- --registry-latest
npm test
The check reports the exact installed AngularTS compatibility target before the
browser suite runs.
2 - Foundations
Global conventions and CSS behavior shared by the entire catalog.
2.1 - direction
Direction and logical text helpers for mixed-locale interfaces.
Use the native dir attribute and logical CSS properties on semantic blocks.
<section dir="rtl">
<p align="start">Logical start aligns for right-to-left.</p>
</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 Direction</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>
<div class="stack">
<section id="direction-default" class="card">
<header>
<h2>LTR</h2>
<p align="start">The chevron points forward.</p>
</header>
<section class="row">
<span aria-hidden="true" class="rtl-flip">-></span>
<span>Settings</span>
</section>
</section>
<section id="direction-rtl" dir="rtl" lang="ar" class="card">
<header>
<h2>RTL</h2>
<p align="start">
تتبع المحاذاة المنطقية واتجاه الأيقونة اتجاه المستند.
</p>
</header>
<section class="row" id="direction-nested">
<span aria-hidden="true" class="rtl-flip">-></span>
<span>الإعدادات</span>
</section>
</section>
</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. Native dir and CSS logical properties.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Authored | Logical text alignment: start or end. |
dir | Authored | Native text direction: ltr, rtl, or auto. |
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
Native dir and CSS logical properties. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use native dir and lang attributes for direction and language. CSS logical properties adapt presentation while native HTML retains those semantics.
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 - Guides
Apply AngularCSS ownership, composition, accessibility, and testing conventions.
These guides cover decisions shared by several components:
- AngularTS ownership
- Composition
- Accessibility
- Testing
Read the individual component reference for exact selectors, attributes, state,
events, and keyboard behavior.
3.1 - AngularTS Ownership
Keep models, validation, bindings, and structural behavior in AngularTS instead of duplicating them in components.
AngularCSS extends AngularTS; it does not replace framework behavior. This rule
keeps components predictable and prevents two state systems from disagreeing.
AngularTS owns application state
Use AngularTS for values, commands, collections, and conditional rendering:
<label for="volume">Volume</label>
<input id="volume" type="range" min="0" max="100" ng-model="volume" />
<output>{{ volume }}</output>
ng-model owns the value while the browser owns the range control. No
AngularCSS directive is needed. Use ng-range-slider on a parent only when two
or more native range inputs must share one visual track.
Prefer native controls for text, checkboxes, radios, ranges, selects, progress,
tables, and labels. Their form submission, browser validation, autofill, mobile
input, and accessibility behavior should remain intact.
Native dialog owns modal focus, Escape closure, background isolation, and
focus restoration. Native details and the Popover API own their disclosure
behavior. AngularCSS supplies styles for these elements.
AngularCSS owns component mechanics
AngularCSS may manage:
- Trigger and panel relationships.
- Composite keyboard navigation and roving focus.
- Focus movement and restoration for composite widgets that need them.
- Required ARIA relationships and state when native HTML cannot express them.
- Component-specific DOM events.
AngularCSS does not own:
- Interpolation or expression parsing.
ng-model, form controllers, or validation rules.ng-if, ng-repeat, or other structural rendering.- Routing, data fetching, persistence, or business commands.
Controlled state
Some components observe concise authored attributes such as open, collapsed,
or native/ARIA state such as aria-selected. Use AngularTS bindings to update
those attributes when application code must control the component. The component
reference marks attributes as input, output, or input/output.
Directive names
AngularCSS avoids collisions with AngularTS. Styling-only elements use native
HTML and roles, so the switch is input[role="switch"]; AngularTS owns model
bindings while the browser owns checkbox state and form behavior.
3.2 - Composition
Combine small AngularCSS primitives into forms, overlays, date pickers, and application navigation.
AngularCSS components expose HTML parts rather than private templates. Compose
them when a workflow needs behavior from more than one primitive.
Combine field, label, input, description, and AngularTS validation:
<div class="field">
<label for="email">Email</label>
<input id="email" name="email" ng-model="profile.email" required />
<p>Used for account notices.</p>
<p ng-if="profileForm.email.invalid" class="field-error">
Enter a valid email.
</p>
</div>
The native input and AngularTS form controller own the value and validity. The
field styles the authored label, helper, and error text around the control.
Date picker
A date picker combines a field, text or date input, popover, and calendar. The
calendar emits angularcss:calendar-select; application code converts the day
into the required date model and updates the input.
Do not introduce a second hidden date model inside the calendar directive.
Command dialog
Place command content inside a dialog. Dialog owns modal focus and closure;
command owns active result navigation; AngularTS owns filtering and command
execution.
Place native details.disclosure inside a sidebar group. Sidebar owns its
global expanded state and responsive hooks; the browser owns nested disclosure.
Composition rules
- Assign each state value to one owner.
- Preserve semantic elements and authored labels.
- Reuse an existing primitive for focus or disclosure behavior.
- Connect composed regions with stable IDs and ARIA relationships.
- Test the complete workflow, not only each isolated primitive.
3.3 - Accessibility
Author names and semantics, understand generated ARIA state, and test complete component compositions.
AngularCSS supplies component mechanics, but accessibility depends on the final
authored HTML. Every component page documents what the directive generates and
what the application must provide.
Start with semantic HTML
Use native elements before adding roles. A button already supports keyboard
activation, a label connects to a form control, and a nav exposes a
navigation landmark.
Use role only for composite patterns without a suitable native element, such
as tabs, menus, and custom listboxes.
Provide accessible names
Visible text should name buttons, fields, landmarks, and overlays. Use
aria-label only when visible text cannot provide the name. Dialog-like
components should include title and description parts so the directive can
connect aria-labelledby and aria-describedby.
Preserve keyboard behavior
- Tab enters and leaves components in normal document order.
- Arrow keys move within composite controls when documented.
- Enter and Space activate buttons and disclosure triggers.
- Escape closes menus and overlays and restores focus where appropriate.
- Disabled items are not activated or selected.
Do not use CSS to visually reorder focusable controls independently of their DOM
order.
Keep focus visible
Application overrides must retain a visible focus indicator with sufficient
contrast. Modal dialogs, alert dialogs, sheets, and drawers trap focus while
open and restore focus to the invoking trigger after closure.
Generated state
Directives generate or synchronize ARIA relationships and data-* state. Do not
hard-code generated IDs. Authored labels and relationships are preserved when
valid, so applications may supply stable IDs for server rendering and tests.
Dynamic feedback
Use status and alert semantics according to urgency. Toasts, spinners, progress,
and field errors must not announce the same change through multiple live
regions.
Test the composition
For every production component:
- Complete the workflow using only a keyboard.
- Confirm focus is always visible and restored after overlays close.
- Inspect the accessibility tree for names, roles, values, and relationships.
- Test validation and dynamic feedback with a screen reader.
- Check zoom, reflow, RTL, reduced motion, and high-contrast settings where
relevant.
3.4 - Testing
Run static quality gates, component browser tests, and the complete documentation example suite.
AngularCSS tests the HTML contract in Chromium with Playwright and validates
source, public entrypoints, documentation inventory, AngularTS overlap, and
forbidden ports with static checks.
Static checks
This command verifies TypeScript, canonical component and element entrypoints,
generated declarations, documentation completeness, component test inventory,
AngularTS directive ownership, CSS isolation, and test ports.
Component tests
PLAYWRIGHT_PORT=4101 npm run test:components -- --reporter=dot
Use an available port other than 3000 or 4000. The default is 4100; set
PLAYWRIGHT_PORT when another local service already owns it.
Documentation tests
PLAYWRIGHT_PORT=4101 npm run test:docs -- --reporter=dot
The documentation suite opens every component and element iframe, verifies that
local AngularTS and AngularCSS assets load, checks that templates compile, and
exercises representative form bindings.
Hugo build
hugo --source docs --destination /tmp/angularcss-docs --cleanDestinationDir
The repository includes precompiled Docsy shell CSS so the site builds with the
standard Hugo binary. The module may still report that extended Hugo is its
preferred environment; that warning does not require a CDN or prevent the build.
Regenerate component references
npm run generate-docs:components
The generator reads canonical TypeScript implementations and updates selectors,
parts, attributes, states, CSS variables, and events on all component pages.
npm run check:docs-content fails when generated reference content is stale.
3.5 - Support
Choose the right channel for AngularCSS questions, defects, proposals, and security reports.
Use
GitHub Discussions
for integration, HTML composition, and customization questions.
Use the issue tracker for
reproducible AngularCSS defects and focused feature proposals. Include:
- A reduced semantic HTML example.
- AngularCSS and AngularTS versions.
- Browser and operating system.
- Expected and observed behavior.
- Keyboard or assistive-technology details when relevant.
Report vulnerabilities through the repository’s private GitHub security advisory
flow. Do not place security-sensitive details in a public issue.
The compatibility and upgrades page describes supported environments and
the latest-version verification command.
3.6 - Contributing
Change AngularCSS while preserving its HTML-first ownership and public API contracts.
Read the repository
contribution guide
before opening a pull request. It defines the HTML, AngularTS, CSS, and
AngularCSS ownership order, local setup, generated documentation workflow, and
public API review process.
For shared presentation changes, update the DTCG 2025.10 source rather than
editing generated token CSS. For catalog changes, keep root classes minimal and
prefer semantic descendants and native attributes. Browser tests must exercise
the built standalone example.
The required local sequence is:
npm run release:build
npm run check
npm test
Keep a pull request focused. Describe the concrete trigger, the resulting
behavior, the public API impact, and the validation performed.
4 - Application examples
Complete AngularTS workflows assembled from AngularCSS components.
Application examples exercise components together under realistic responsive,
state, accessibility, and information-density constraints.
4.1 - Bookings operations
An enterprise reservation workflow assembled from AngularCSS components.
This AngularTS application composes sidebar, input group, tabs, badge, avatar,
scroll area, empty, button, and dialog components into a responsive upcoming
bookings workflow. Search, status filtering, booking selection, dialog state,
and mobile navigation are functional. All scripts, styles, and Lucide icons are
bundled locally.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Bookings</title>
<link rel="stylesheet" href="../../../css/preflight.css" />
<link rel="stylesheet" href="../../../css/angular.css" />
<link rel="stylesheet" href="./bookings.css" />
<script src="../../../js/angular-ts.umd.js"></script>
<script src="../../../js/angular-css.umd.js"></script>
<script src="./bookings.js"></script>
</head>
<body
ng-app="bookingsDemo"
ng-controller="BookingsController as bookings"
ng-cloak
>
<div class="booking-shell" data-testid="booking-shell">
<nav class="booking-rail" aria-label="Application navigation">
<a class="booking-brand" href="./" aria-label="OrbitPass home">O</a>
<div class="booking-rail-primary">
<a href="#search" aria-label="Search"
><span ng-icon="search"></span
></a>
<a class="is-active" href="#bookings" aria-label="Bookings">
<span ng-icon="bookings"></span><small>Bookings</small>
</a>
<a href="#support" aria-label="Support">
<span ng-icon="support"></span><small>Support</small>
</a>
<a href="#admin" aria-label="Admin">
<span ng-icon="settings"></span><small>Admin</small>
</a>
</div>
<div class="booking-rail-footer">
<button type="button" aria-label="Notifications">
<span ng-icon="bell"></span><span class="notification-dot"></span>
</button>
<span size="sm" class="avatar">
<span>EE</span>
<output aria-label="Online"></output>
</span>
</div>
</nav>
<aside
id="booking-sidebar"
class="booking-secondary"
ng-sidebar
style="--sidebar-width: 14rem"
>
<div>
<header class="booking-sidebar-header">
<strong>Bookings</strong>
<button size="icon-sm" variant="ghost" aria-label="Add booking">
<span ng-icon="plus"></span>
</button>
</header>
<hr />
<nav>
<section>
<div>
<ul>
<li>
<button aria-current="page">
<span ng-icon="bookings"></span><span>Upcoming</span>
</button>
<output>40</output>
</li>
<li>
<button>
<span ng-icon="clock"></span><span>Past</span>
</button>
<output>0</output>
</li>
<li>
<button>
<span ng-icon="customers"></span><span>Customers</span>
</button>
<output>21</output>
</li>
<li>
<button>
<span ng-icon="invoices"></span><span>Invoices</span>
</button>
<output>0</output>
</li>
</ul>
</div>
</section>
</nav>
<footer class="booking-sidebar-footer">
<span class="muted">Signed in as</span>
<strong>Emma Executive</strong>
</footer>
</div>
</aside>
<main class="booking-main" id="bookings">
<header class="booking-toolbar">
<div class="booking-title-row">
<button
class="booking-mobile-menu"
size="icon-sm"
variant="outline"
aria-controls="booking-sidebar"
aria-label="Toggle booking navigation"
>
<span ng-icon="menu"></span>
</button>
<div>
<span class="booking-eyebrow">Bookings</span>
<h1>Upcoming</h1>
</div>
</div>
<div class="booking-search input-group">
<span ng-icon="search"></span>
<input
ng-model="bookings.query"
data-change="bookings.updateVisible()"
type="search"
aria-label="Search bookings"
placeholder="Search bookings"
/>
<span align="inline-end">
<kbd>/</kbd>
</span>
</div>
</header>
<div class="booking-filterbar">
<nav variant="line" aria-label="Booking status">
<button
type="button"
aria-pressed="{{ bookings.status === 'All' }}"
ng-click="bookings.setStatus('All')"
>
All
</button>
<button
ng-click="bookings.setStatus('Confirmed')"
aria-pressed="{{ bookings.status === 'Confirmed' }}"
>
Confirmed
</button>
<button
ng-click="bookings.setStatus('Pending')"
aria-pressed="{{ bookings.status === 'Pending' }}"
>
Pending
</button>
<button
ng-click="bookings.setStatus('Change Requested')"
aria-pressed="{{ bookings.status === 'Change Requested' }}"
>
Change requested
</button>
</nav>
<span class="booking-result-count">
<strong ng-bind="bookings.visibleCount"></strong> results
</span>
</div>
<section
class="booking-scroll scroll-area"
tabindex="0"
aria-label="Bookings"
>
<div class="booking-list" aria-live="polite">
<article
class="booking-row"
ng-repeat="booking in bookings.bookings"
ng-show="booking.visible"
>
<button
class="booking-row-trigger"
type="button"
aria-controls="booking-detail-dialog-content"
commandfor="booking-detail-dialog-content"
command="show-modal"
ng-click="bookings.select(booking)"
>
<span class="booking-summary">
<span
class="booking-reference"
ng-bind="booking.reference"
></span>
<span
><span ng-icon="ticket"></span
><span ng-bind="booking.service"></span
></span>
<span
><span ng-icon="rocket"></span
><span ng-bind="booking.vessel"></span
></span>
<span
status="{{ booking.status }}"
ng-bind="booking.status"
class="badge"
></span>
</span>
<span class="booking-route">
<span class="booking-place">
<strong ng-bind="booking.origin"></strong>
<span ng-bind="booking.departure"></span>
</span>
<span class="booking-journey" aria-hidden="true">
<span class="booking-route-line"></span>
<span ng-icon="plane"></span>
<small ng-bind="booking.duration"></small>
</span>
<span class="booking-place booking-destination">
<strong ng-bind="booking.destination"></strong>
<span ng-bind="booking.arrival"></span>
</span>
</span>
<span class="booking-meta">
<span
><span ng-icon="customer"></span
><span ng-bind="booking.customer"></span
></span>
<span
><span ng-icon="ticket"></span
><span ng-bind="booking.customerId"></span
></span>
<span
><span ng-icon="home"></span
><span ng-bind="booking.cabin"></span
></span>
<span
><span ng-icon="luggage"></span
><span ng-bind="booking.luggage"></span
></span>
<span
><span ng-icon="luggage"></span
><span ng-bind="booking.allowance"></span
></span>
</span>
</button>
</article>
<section ng-show="bookings.empty" class="booking-empty empty">
<figure>
<span ng-icon="search"></span>
</figure>
<h2>No bookings found</h2>
<p>Try a different search or status.</p>
</section>
</div>
</section>
</main>
</div>
<section id="booking-detail-dialog" class="booking-dialog dialog">
<dialog
id="booking-detail-dialog-content"
closedby="any"
aria-labelledby="booking-dialog-title"
aria-describedby="booking-dialog-description"
>
<header>
<span
class="booking-dialog-reference"
ng-bind="bookings.selected.reference"
></span>
<h2 id="booking-dialog-title">Booking details</h2>
<p id="booking-dialog-description">
<span ng-bind="bookings.selected.customer"></span> traveling from
<span ng-bind="bookings.selected.origin"></span> to
<span ng-bind="bookings.selected.destination"></span>.
</p>
</header>
<dl class="booking-detail-grid">
<div>
<dt>Service</dt>
<dd ng-bind="bookings.selected.service"></dd>
</div>
<div>
<dt>Status</dt>
<dd ng-bind="bookings.selected.status"></dd>
</div>
<div>
<dt>Departure</dt>
<dd ng-bind="bookings.selected.departure"></dd>
</div>
<div>
<dt>Arrival</dt>
<dd ng-bind="bookings.selected.arrival"></dd>
</div>
<div class="booking-detail-wide">
<dt>Cabin</dt>
<dd ng-bind="bookings.selected.cabin"></dd>
</div>
</dl>
<footer>
<button
commandfor="booking-detail-dialog-content"
command="close"
variant="outline"
>
Close
</button>
<button>Open booking</button>
</footer>
</dialog>
</section>
</body>
</html>
5 - Elements
Native HTML elements styled directly, without AngularCSS runtime behavior.
5.1 - button
Action controls with variant and size styling hooks.
Native button elements and button-type inputs are styled directly. Set
variant/size attributes for variants and spacing. A link may opt into the
same presentation with a variant attribute when it navigates to another
location.
<div class="row">
<button>Default</button>
<button variant="outline">Outline</button>
<button size="sm">Small</button>
</div>
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 Button</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="button-demo">
<div class="row visual-example">
<button variant="outline">Button</button>
<button variant="outline" size="icon" aria-label="Submit">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="m5 12 7-7 7 7M12 19V5"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</body>
</html>
Variant workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Button 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="button-default button-destructive button-ghost button-icon button-link button-outline button-render button-rounded button-rtl button-secondary button-size button-spinner button-with-icon"
>
<main class="workflow-stack">
<div class="workflow-row" aria-label="Button variants">
<button>Button</button>
<button variant="secondary">Secondary</button>
<button variant="destructive">Destructive</button>
<button variant="outline">Outline</button>
<button variant="ghost">Ghost</button>
<button variant="link">Link</button>
</div>
<div class="workflow-row" aria-label="Status buttons">
<button variant="info">Information</button>
<button variant="success">Success</button>
<button variant="warning">Warning</button>
</div>
<div class="workflow-row workflow-sizes" aria-label="Button sizes">
<button size="xs" variant="outline">Extra Small</button>
<button
size="icon-xs"
variant="outline"
aria-label="Submit extra small"
>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<button size="sm" variant="outline">Small</button>
<button size="icon-sm" variant="outline" aria-label="Submit small">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<button variant="outline">Default</button>
<button size="icon" variant="outline" aria-label="Submit default">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<button size="lg" variant="outline">Large</button>
<button size="icon-lg" variant="outline" aria-label="Submit large">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
<div class="workflow-row" aria-label="Rounded and icon buttons">
<a href="#login" variant="secondary" size="sm">Login</a>
<button type="submit" class="button-rounded">Get Started</button>
<button
class="button-rounded"
variant="outline"
size="icon"
aria-label="Continue"
>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="m5 12 7-7 7 7M12 19V5"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<button variant="outline">
<svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M6 3v12M18 9v12M6 9c6 0 6 6 12 6M18 3v3"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
New Branch
</button>
<button variant="outline">
Fork
<svg
icon="inline-end"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M6 3v12M18 9v12M6 9c6 0 6 6 12 6M18 3v3"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</button>
</div>
<div class="workflow-row" aria-label="Loading buttons">
<button variant="outline" disabled>
<svg
icon="inline-start"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
Generating
</button>
<button variant="secondary" aria-disabled="true">
Downloading
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</button>
</div>
<div class="workflow-row" dir="rtl" aria-label="RTL buttons">
<button variant="outline">زر</button>
<button variant="destructive">حذف</button>
<button variant="outline">
إرسال
<svg
icon="inline-end"
class="rtl-flip"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="m9 18 6-6-6-6"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
</div>
</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 button and link activation.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-disabled | Authored | Semantic disabled state. |
aria-haspopup | Authored | Type of popup controlled by the trigger. |
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
icon | Authored | Icon position: inline-start or inline-end. |
size | Authored | Size: xs, sm, default, lg, icon-xs, icon-sm, icon, or icon-lg. |
variant | Authored | Style: default, secondary, outline, ghost, link, destructive, info, success, or warning. |
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
Native button and link activation. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native button whenever the control performs an action. Keep an accessible name, preserve visible focus, and use disabled for unavailable native controls.
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.2 - checkbox
Native checkbox control styled from native state.
Use a native checkbox input. AngularCSS styles it directly; native input state
and AngularTS ng-model remain the source of truth. Use role="switch" only
when the checkbox needs switch semantics and presentation.
<div orientation="horizontal" class="field">
<input id="terms" name="terms" type="checkbox" ng-model="terms" />
<label for="terms"> Accept terms </label>
</div>
Set the native HTMLInputElement.indeterminate property from application code
when a mixed selection is needed. Native :indeterminate state owns both the
visual and accessibility contract; AngularCSS does not create a second checkbox
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 Checkbox</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="terms=false;termsDetails=true;wrappedNotifications=false"
data-example="checkbox-demo"
>
<div class="visual-example field-group">
<div orientation="horizontal" class="field">
<input
id="terms-checkbox"
name="terms-checkbox"
type="checkbox"
ng-model="terms"
/>
<label for="terms-checkbox">Accept terms and conditions</label>
</div>
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-2"
name="terms-checkbox-2"
type="checkbox"
ng-model="termsDetails"
/>
<section>
<label for="terms-checkbox-2">Accept terms and conditions</label>
<p>By clicking this checkbox, you agree to the terms.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="toggle-checkbox"
name="toggle-checkbox"
type="checkbox"
disabled
/>
<label for="toggle-checkbox">Enable notifications</label>
</div>
<label>
<div orientation="horizontal" class="field">
<input
id="toggle-checkbox-2"
name="toggle-checkbox-2"
type="checkbox"
ng-model="wrappedNotifications"
/>
<section>
<strong>Enable notifications</strong>
<small>
You can enable or disable notifications at any time.
</small>
</section>
</div>
</label>
<output class="visually-hidden" aria-live="polite">
Terms {{ terms ? 'accepted' : 'not accepted' }}. Detailed terms {{
termsDetails ? 'accepted' : 'not accepted' }}. Notifications {{
wrappedNotifications ? 'enabled' : 'disabled' }}.
</output>
</div>
</body>
</html>
States, group, and RTL
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Checkbox 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="basic=false;described=true;hardDisks=true;externalDisks=true;cds=false;servers=false;rtlTerms=false;rtlDetails=true;rtlNotifications=false"
data-example="checkbox-basic checkbox-description checkbox-disabled checkbox-group checkbox-invalid checkbox-rtl"
>
<main class="checkbox-workflow-grid" aria-label="Checkbox workflows">
<section
class="checkbox-workflow"
aria-labelledby="checkbox-basic-heading"
>
<h2 id="checkbox-basic-heading">Basic</h2>
<div class="checkbox-workflow-narrow field-group">
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-basic"
name="terms-checkbox-basic"
type="checkbox"
ng-model="basic"
/>
<label for="terms-checkbox-basic"
>Accept terms and conditions</label
>
</div>
</div>
</section>
<section
class="checkbox-workflow"
aria-labelledby="checkbox-description-heading"
>
<h2 id="checkbox-description-heading">Description</h2>
<div class="checkbox-workflow-description field-group">
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-desc"
name="terms-checkbox-desc"
type="checkbox"
ng-model="described"
/>
<section>
<label for="terms-checkbox-desc"
>Accept terms and conditions</label
>
<p>
By clicking this checkbox, you agree to the terms and
conditions.
</p>
</section>
</div>
</div>
</section>
<section
class="checkbox-workflow"
aria-labelledby="checkbox-disabled-heading"
>
<h2 id="checkbox-disabled-heading">Disabled</h2>
<div class="checkbox-workflow-narrow field-group">
<div orientation="horizontal" class="field">
<input
id="toggle-checkbox-disabled"
name="toggle-checkbox-disabled"
type="checkbox"
disabled
/>
<label for="toggle-checkbox-disabled">Enable notifications</label>
</div>
</div>
</section>
<section
class="checkbox-workflow"
aria-labelledby="checkbox-invalid-heading"
>
<h2 id="checkbox-invalid-heading">Invalid</h2>
<div class="checkbox-workflow-narrow field-group">
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-invalid"
name="terms-checkbox-invalid"
type="checkbox"
aria-invalid="true"
/>
<label for="terms-checkbox-invalid"
>Accept terms and conditions</label
>
</div>
</div>
</section>
<section
class="checkbox-workflow"
aria-labelledby="checkbox-group-heading"
>
<h2 id="checkbox-group-heading">Group</h2>
<fieldset class="field-set">
<legend variant="label">Show these items on the desktop:</legend>
<p>Select the items you want to show on the desktop.</p>
<div class="checkbox-preference-group field-group">
<div orientation="horizontal" class="field">
<input id="hard-disks" type="checkbox" ng-model="hardDisks" />
<label for="hard-disks">Hard disks</label>
</div>
<div orientation="horizontal" class="field">
<input
id="external-disks"
type="checkbox"
ng-model="externalDisks"
/>
<label for="external-disks">External disks</label>
</div>
<div orientation="horizontal" class="field">
<input id="cds-dvds" type="checkbox" ng-model="cds" />
<label for="cds-dvds">CDs, DVDs, and iPods</label>
</div>
<div orientation="horizontal" class="field">
<input
id="connected-servers"
type="checkbox"
ng-model="servers"
/>
<label for="connected-servers">Connected servers</label>
</div>
</div>
</fieldset>
</section>
<section
class="checkbox-workflow checkbox-workflow-rtl"
aria-labelledby="checkbox-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="checkbox-rtl-heading">من اليمين إلى اليسار</h2>
<div class="field-group">
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-rtl"
type="checkbox"
ng-model="rtlTerms"
/>
<label for="terms-checkbox-rtl">قبول الشروط والأحكام</label>
</div>
<div orientation="horizontal" class="field">
<input
id="terms-checkbox-2-rtl"
type="checkbox"
ng-model="rtlDetails"
/>
<section>
<label for="terms-checkbox-2-rtl">قبول الشروط والأحكام</label>
<p>بالنقر على هذا المربع، فإنك توافق على الشروط.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input id="toggle-checkbox-rtl" type="checkbox" disabled />
<label for="toggle-checkbox-rtl">تفعيل الإشعارات</label>
</div>
<label>
<div orientation="horizontal" class="field">
<input
id="toggle-checkbox-2-rtl"
type="checkbox"
ng-model="rtlNotifications"
/>
<section>
<strong>تفعيل الإشعارات</strong>
<small>يمكنك تفعيل أو إلغاء تفعيل الإشعارات في أي وقت.</small>
</section>
</div>
</label>
</div>
</section>
<output class="visually-hidden" aria-live="polite">
Basic {{ basic }}. Described {{ described }}. Hard disks {{ hardDisks
}}. External disks {{ externalDisks }}. CDs {{ cds }}. Servers {{
servers }}.
</output>
</main>
</body>
</html>
Table selection
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Checkbox Compositions</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="selection={allRows:false};rows=[{id:'1',name:'Sarah Chen',email:'sarah.chen@example.com',role:'Admin',selected:true},{id:'2',name:'Marcus Rodriguez',email:'marcus.rodriguez@example.com',role:'User',selected:false},{id:'3',name:'Priya Patel',email:'priya.patel@example.com',role:'User',selected:false},{id:'4',name:'David Kim',email:'david.kim@example.com',role:'Editor',selected:false}]"
data-example="checkbox-table"
>
<main class="checkbox-table-demo" aria-label="Checkbox table composition">
<figure>
<table aria-label="Team members">
<thead>
<tr>
<th scope="col" class="checkbox-table-select">
<input
id="select-all-checkbox"
name="select-all-checkbox"
type="checkbox"
ng-model="selection.allRows"
ng-change="rows[0].selected=selection.allRows;rows[1].selected=selection.allRows;rows[2].selected=selection.allRows;rows[3].selected=selection.allRows"
aria-label="Select all rows"
/>
</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Role</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows" aria-selected="{{ row.selected }}">
<td class="checkbox-table-select">
<input
id="row-{{ row.id }}-checkbox"
name="row-{{ row.id }}-checkbox"
type="checkbox"
ng-model="row.selected"
ng-change="selection.allRows=rows[0].selected && rows[1].selected && rows[2].selected && rows[3].selected"
aria-label="Select {{ row.name }}"
/>
</td>
<td class="checkbox-table-name">{{ row.name }}</td>
<td>{{ row.email }}</td>
<td>{{ row.role }}</td>
</tr>
</tbody>
</table>
</figure>
<output class="visually-hidden" aria-live="polite">
Sarah Chen {{ rows[0].selected ? 'selected' : 'not selected' }}. Marcus
Rodriguez {{ rows[1].selected ? 'selected' : 'not selected' }}. Priya
Patel {{ rows[2].selected ? 'selected' : 'not selected' }}. David Kim {{
rows[3].selected ? 'selected' : 'not selected' }}.
</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. Native checkbox state and validation.
Anatomy
Root styling selector
input[type="checkbox"]:not([role="switch"])
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
checked | Authored | Initial native checked state. |
disabled | Authored | Disables native or component interaction. |
required | Authored | Marks a native form value as required. |
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
Native checkbox state and validation. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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.3 - dialog
Modal dialog structure
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>
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
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.
5.4 - input
Native form text entry styled directly by AngularCSS.
Use a native input. AngularCSS styles data-entry input types directly, while
the browser and AngularTS own values, events, validation, required state,
disabled state, and form behavior.
<input placeholder="Jane Doe" /> <input placeholder="Disabled" disabled />
Use the native size attribute when a compact control should size to its
content. The control retains a max-width of 100%; browsers without
field-sizing use the requested number of visible characters.
<input value="Compact" size="7" />
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 Input</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="search=''; status=''">
<div class="stack">
<label for="docs-input-search">Search</label>
<input id="docs-input-search" placeholder="Search" ng-model="search" />
<output class="output"> Value: {{ search ? search : "empty" }} </output>
<label for="docs-input-compact">Content-sized</label>
<input id="docs-input-compact" value="Compact" size="7" />
<label for="docs-input-disabled">Disabled</label>
<input id="docs-input-disabled" placeholder="Disabled" disabled />
<label for="docs-input-invalid">Invalid</label>
<input
id="docs-input-invalid"
placeholder="Invalid"
aria-invalid="true"
/>
<label for="docs-input-file">File</label>
<input id="docs-input-file" type="file" />
</div>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Input 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="inputState={basic:'',apiKey:'',username:'',name:'',email:'',firstName:'',lastName:'',search:'',website:'',required:'',country:'us',formName:'',formEmail:'',phone:'',address:'',message:'Ready'}"
>
<main class="input-workflow-grid" aria-label="Input workflows">
<section data-example="input-basic" class="input-workflow">
<input
ng-model="inputState.basic"
placeholder="Enter text"
aria-label="Basic input"
/>
</section>
<section data-example="input-demo" class="input-workflow">
<div class="field">
<label for="input-demo-api-key">API Key</label>
<input
id="input-demo-api-key"
type="password"
ng-model="inputState.apiKey"
placeholder="sk-..."
/>
<p>Your API key is encrypted and stored securely.</p>
</div>
</section>
<section data-example="input-disabled" class="input-workflow">
<div class="field">
<label for="input-demo-disabled">Email</label>
<input
id="input-demo-disabled"
type="email"
placeholder="Email"
disabled
/>
<p>This field is currently disabled.</p>
</div>
</section>
<section data-example="input-invalid" class="input-workflow">
<div class="field">
<label for="input-invalid-workflow">Invalid Input</label>
<input
id="input-invalid-workflow"
placeholder="Error"
aria-invalid="true"
/>
<p>This field contains validation errors.</p>
</div>
</section>
<section data-example="input-required" class="input-workflow">
<div class="field">
<label for="input-required-workflow"
>Required Field <span class="input-required-mark">*</span></label
>
<input
id="input-required-workflow"
ng-model="inputState.required"
placeholder="This field is required"
required
/>
<p>This field must be filled out.</p>
</div>
</section>
<section data-example="input-file" class="input-workflow">
<div class="field">
<label for="input-picture">Picture</label>
<input id="input-picture" type="file" />
<p>Select a picture to upload.</p>
</div>
</section>
<section data-example="input-field" class="input-workflow">
<div class="field">
<label for="input-field-username">Username</label>
<input
id="input-field-username"
ng-model="inputState.username"
placeholder="Enter your username"
/>
<p>Choose a unique username for your account.</p>
</div>
</section>
<section data-example="input-badge" class="input-workflow">
<div class="field">
<label for="input-webhook"
>Webhook URL
<span variant="secondary" class="input-label-badge badge"
>Beta</span
></label
>
<input
id="input-webhook"
type="url"
placeholder="https://api.example.com/webhook"
/>
</div>
</section>
<section
data-example="input-grid"
class="input-workflow input-workflow-wide"
>
<div class="input-name-grid field-group">
<div class="field">
<label for="input-first-name">First Name</label
><input
id="input-first-name"
ng-model="inputState.firstName"
placeholder="Jordan"
/>
</div>
<div class="field">
<label for="input-last-name">Last Name</label
><input
id="input-last-name"
ng-model="inputState.lastName"
placeholder="Lee"
/>
</div>
</div>
</section>
<section
data-example="input-inline"
class="input-workflow input-workflow-wide"
>
<div orientation="horizontal" class="input-inline-demo field">
<input
type="search"
ng-model="inputState.search"
placeholder="Search..."
aria-label="Inline search"
/>
<button
type="button"
ng-click="inputState.message='Search '+inputState.search"
>
Search
</button>
</div>
</section>
<section data-example="input-button-group" class="input-workflow">
<div class="field">
<label for="input-button-group-workflow">Search</label>
<div role="group">
<input
id="input-button-group-workflow"
placeholder="Type to search..."
/><button
variant="outline"
type="button"
ng-click="inputState.message='Button group search'"
>
Search
</button>
</div>
</div>
</section>
<section data-example="input-input-group" class="input-workflow">
<div class="field">
<label for="input-group-url">Website URL</label>
<div class="input-group">
<input
id="input-group-url"
ng-model="inputState.website"
placeholder="example.com"
/>
<div>https://</div>
<div align="inline-end" aria-label="Website URL information">ⓘ</div>
</div>
</div>
</section>
<form
data-example="input-fieldgroup"
class="input-workflow input-workflow-form"
ng-submit="inputState.message='Submitted '+inputState.name"
>
<div class="field-group">
<div class="field">
<label for="fieldgroup-name">Name</label
><input
id="fieldgroup-name"
ng-model="inputState.name"
placeholder="Jordan Lee"
/>
</div>
<div class="field">
<label for="fieldgroup-email">Email</label
><input
id="fieldgroup-email"
type="email"
ng-model="inputState.email"
placeholder="name@example.com"
/>
<p>We'll send updates to this address.</p>
</div>
<div orientation="horizontal" class="input-form-actions field">
<button
type="reset"
variant="outline"
ng-click="inputState.name='';inputState.email=''"
>
Reset</button
><button type="submit">Submit</button>
</div>
</div>
</form>
<form
data-example="input-form"
class="input-workflow input-workflow-form input-workflow-form-large"
ng-submit="inputState.message='Contact submitted '+inputState.formName"
>
<div class="field-group">
<div class="field">
<label for="form-name">Name</label
><input
id="form-name"
ng-model="inputState.formName"
placeholder="Evil Rabbit"
required
/>
</div>
<div class="field">
<label for="form-email">Email</label
><input
id="form-email"
type="email"
ng-model="inputState.formEmail"
placeholder="john@example.com"
/>
<p>We'll never share your email with anyone.</p>
</div>
<div class="input-name-grid">
<div class="field">
<label for="form-phone">Phone</label
><input
id="form-phone"
type="tel"
ng-model="inputState.phone"
placeholder="+1 (555) 123-4567"
/>
</div>
<div class="field">
<label for="form-country">Country</label>
<select id="form-country" ng-model="inputState.country">
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
<option value="ca">Canada</option>
</select>
</div>
</div>
<div class="field">
<label for="form-address">Address</label
><input
id="form-address"
ng-model="inputState.address"
placeholder="123 Main St"
/>
</div>
<div orientation="horizontal" class="input-form-actions field">
<button
type="button"
variant="outline"
ng-click="inputState.message='Cancelled'"
>
Cancel</button
><button type="submit">Submit</button>
</div>
</div>
</form>
<section
data-example="input-rtl"
class="input-workflow"
dir="rtl"
lang="ar"
>
<div class="field">
<label for="input-rtl-api-key">مفتاح API</label
><input
id="input-rtl-api-key"
type="password"
dir="rtl"
placeholder="sk-..."
/>
<p>مفتاح API الخاص بك مشفر ومخزن بأمان.</p>
</div>
</section>
<output class="input-workflow-output"> {{ inputState.message }} </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. Native input behavior and AngularTS models.
Anatomy
Root styling selector
input:not([type="button"], [type="checkbox"], [type="color"], [type="hidden"], [type="image"], [type="radio"], [type="range"], [type="reset"], [type="submit"])
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
disabled | Authored | Disables native or component interaction. |
size | Authored | Native number of visible characters; also enables content sizing when supported. |
type | Authored | Native input kind, such as text, email, password, number, search, tel, or url. |
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
Input is a native control styled directly by element and type. AngularTS and the browser own value, events, model synchronization, validation, disabled and required state, and form submission. AngularCSS registers no input directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native input with a visible label. Preserve native type, name, autocomplete, required, disabled, and validation semantics; use AngularTS ng-model for application state and aria-invalid when application validation must be exposed explicitly.
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.5 - kbd
Keyboard shortcut hint
Use native kbd elements. Place related keys next to each other in a span.
<span>
<kbd>Ctrl</kbd>
<kbd>K</kbd>
</span>
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 Kbd</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="kbdAction='Ready'"
data-example="kbd-button kbd-demo kbd-input-group kbd-rtl kbd-tooltip"
>
<main class="visual-example">
<section class="kbd-row">
<span>Open command menu</span>
<span><kbd>Ctrl</kbd><kbd>K</kbd></span>
<span>or</span>
<kbd aria-label="Slash">/</kbd>
</section>
<button variant="outline" type="button" ng-click="kbdAction='Saved'">
Save changes
<span><kbd>Ctrl</kbd><kbd>S</kbd></span>
</button>
<div class="input-group">
<input placeholder="Search..." aria-label="Search with shortcut" />
<div align="inline-end">
<kbd>⌘K</kbd>
</div>
</div>
<span ng-tooltip>
<button variant="outline" type="button">Keyboard help</button>
<span side="top">Press <kbd>?</kbd> to open help.</span>
</span>
<section class="kbd-row" dir="rtl" lang="ar">
<span>فتح قائمة الأوامر</span>
<span><kbd>Ctrl</kbd><kbd>K</kbd></span>
</section>
<output class="kbd-output">{{ kbdAction }}</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. Native keyboard-input semantics.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
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
Native keyboard-input semantics. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Keep the text available to assistive technology and add an accessible label when a visual abbreviation would otherwise be ambiguous.
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.6 - label
Label helper that mirrors required/disabled state from its associated control.
Use a native label and connect it with for.
<label for="email">Email</label> <input id="email" required />
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 Label</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="labelTerms=false;labelTermsRtl=false"
data-example="label-demo label-rtl"
>
<main class="visual-example">
<form class="label-control-contract" aria-label="Label state contract">
<label for="email">Email</label>
<input id="email" placeholder="Email" />
<label for="name">Name</label>
<input id="name" placeholder="Name" />
</form>
<section class="label-checkbox-demo" aria-label="Label checkbox">
<input id="label-terms" type="checkbox" ng-model="labelTerms" />
<label for="label-terms">Accept terms and conditions</label>
</section>
<section
class="label-checkbox-demo"
aria-label="تسمية خانة الاختيار"
dir="rtl"
lang="ar"
>
<input id="label-terms-rtl" type="checkbox" ng-model="labelTermsRtl" />
<label for="label-terms-rtl">قبول الشروط والأحكام</label>
</section>
<output class="label-output">
Terms: {{ labelTerms ? 'accepted' : 'not accepted' }} · الشروط: {{
labelTermsRtl ? 'مقبولة' : 'غير مقبولة' }}
</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. Native form-control association.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
for | Authored | ID of the native form control associated with a label. |
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
Native form-control association. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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.7 - progress
Task completion indicator
Use native progress. Compose its label and value with native label and
output elements when needed.
<div>
<label id="upload-progress-label">Upload progress</label>
<output>56%</output>
<progress
value="56"
max="100"
aria-labelledby="upload-progress-label"
></progress>
</div>
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 Progress</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>
<script src="../../js/progress-demo.umd.js"></script>
</head>
<body
ng-app="progressDemo"
ng-controller="ProgressDemoController"
ng-cloak
data-example="progress-demo progress-label"
>
<main class="visual-example">
<section aria-labelledby="progress-timed-title">
<h2 id="progress-timed-title" class="visually-hidden">
Loading progress
</h2>
<progress
value="{{ demoValue }}"
max="100"
aria-labelledby="progress-timed-title"
class="progress-demo-timed"
></progress>
</section>
<section>
<div class="progress-demo-labeled">
<label id="upload-progress-label"> Upload progress </label>
<output for="upload-progress">56%</output>
<progress
id="upload-progress"
value="56"
max="100"
aria-labelledby="upload-progress-label"
></progress>
</div>
</section>
</main>
</body>
</html>
Controlled and RTL
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Progress 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="progressWorkflow={controlled:50}"
data-example="progress-controlled progress-rtl"
>
<main class="progress-workflows visual-example">
<section aria-labelledby="progress-controlled-title">
<div class="workflow-heading">
<h2 id="progress-controlled-title">Controlled</h2>
<output for="progress-controlled-slider">
{{ progressWorkflow.controlled }}%
</output>
</div>
<progress
value="{{ progressWorkflow.controlled }}"
max="100"
aria-labelledby="progress-controlled-title"
></progress>
<input
ng-range-slider
id="progress-controlled-slider"
type="range"
min="0"
max="100"
step="1"
ng-model="progressWorkflow.controlled"
aria-label="Progress value"
/>
</section>
<section lang="ar">
<div dir="rtl">
<label id="rtl-upload-progress-label"> تقدم الرفع </label>
<output for="rtl-upload-progress">٥٦%</output>
<progress
id="rtl-upload-progress"
value="56"
max="100"
aria-labelledby="rtl-upload-progress-label"
></progress>
</div>
</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 progress semantics and state.
Anatomy
Root styling selector
Semantic structure
Use a native progress element. For a visible label and value, place direct native label, output, and progress children in one div; AngularCSS recognizes that semantic structure without another class.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
dir | Authored | Text and interaction direction: ltr or rtl. |
max | Authored | Maximum native or component value. |
value | Authored | Native value or authored component value. |
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
The native progress element owns progressbar semantics and determinate or indeterminate state. Native label and output elements provide optional context. AngularTS may bind value; AngularCSS registers no progress directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give every native progress element an accessible name with label, aria-label, or aria-labelledby. Set value and max for determinate progress; omit value for indeterminate progress.
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.8 - radio-group
Native radio input grouping with role and focus behavior.
Use a native fieldset with a legend and radio inputs. AngularCSS recognizes
the semantic group and styles its native radio descendants directly.
<fieldset>
<div class="field" orientation="horizontal">
<input id="default" name="density" type="radio" value="default" />
<label for="default">Default</label>
</div>
</fieldset>
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 Radio Group</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="density='comfortable'"
data-example="radio-group-demo"
>
<fieldset class="visual-example">
<legend class="visually-hidden">Density</legend>
<div orientation="horizontal" class="field">
<input
id="density-default"
name="density"
type="radio"
value="default"
ng-model="density"
/>
<label for="density-default">Default</label>
</div>
<div orientation="horizontal" class="field">
<input
id="density-comfortable"
name="density"
type="radio"
value="comfortable"
ng-model="density"
/>
<label for="density-comfortable">Comfortable</label>
</div>
<div orientation="horizontal" class="field">
<input
id="density-compact"
name="density"
type="radio"
value="compact"
ng-model="density"
/>
<label for="density-compact">Compact</label>
</div>
<output class="visually-hidden" aria-live="polite">
Selected: <span ng-bind="density"></span>
</output>
</fieldset>
</body>
</html>
Reference Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Radio Group 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="planType='plus'; densityDescription='comfortable'; disabledChoice='option2'; subscription='monthly'; notification='email'; rtlDensity='comfortable'"
data-example="radio-group-choice-card radio-group-description radio-group-disabled radio-group-fieldset radio-group-invalid radio-group-rtl"
>
<main class="radio-group-workflows">
<section class="radio-workflow-section" aria-label="Plan choice cards">
<fieldset class="radio-choice-list">
<label for="plus-plan" class="radio-choice">
<div orientation="horizontal" class="field">
<span>
<strong>Plus</strong>
<small> For individuals and small teams. </small>
</span>
<input
id="plus-plan"
name="plan-type"
type="radio"
value="plus"
ng-model="planType"
/>
</div>
</label>
<label for="pro-plan" class="radio-choice">
<div orientation="horizontal" class="field">
<span>
<strong>Pro</strong>
<small> For growing businesses. </small>
</span>
<input
id="pro-plan"
name="plan-type"
type="radio"
value="pro"
ng-model="planType"
/>
</div>
</label>
<label for="enterprise-plan" class="radio-choice">
<div orientation="horizontal" class="field">
<span>
<strong>Enterprise</strong>
<small> For large teams and enterprises. </small>
</span>
<input
id="enterprise-plan"
name="plan-type"
type="radio"
value="enterprise"
ng-model="planType"
/>
</div>
</label>
</fieldset>
</section>
<section class="radio-workflow-section" aria-label="Density descriptions">
<fieldset class="radio-description-list">
<div orientation="horizontal" class="field">
<input
id="desc-r1"
name="density-description"
type="radio"
value="default"
ng-model="densityDescription"
/>
<section>
<label for="desc-r1">Default</label>
<p>Standard spacing for most use cases.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="desc-r2"
name="density-description"
type="radio"
value="comfortable"
ng-model="densityDescription"
/>
<section>
<label for="desc-r2">Comfortable</label>
<p>More space between elements.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="desc-r3"
name="density-description"
type="radio"
value="compact"
ng-model="densityDescription"
/>
<section>
<label for="desc-r3">Compact</label>
<p>Minimal spacing for dense layouts.</p>
</section>
</div>
</fieldset>
</section>
<section class="radio-workflow-section" aria-label="Disabled radio">
<fieldset class="radio-simple-list">
<div orientation="horizontal" class="field">
<input
id="disabled-1"
name="disabled-choice"
type="radio"
value="option1"
disabled
ng-model="disabledChoice"
/>
<label for="disabled-1" class="radio-plain-label"> Disabled </label>
</div>
<div orientation="horizontal" class="field">
<input
id="disabled-2"
name="disabled-choice"
type="radio"
value="option2"
ng-model="disabledChoice"
/>
<label for="disabled-2" class="radio-plain-label"> Option 2 </label>
</div>
<div orientation="horizontal" class="field">
<input
id="disabled-3"
name="disabled-choice"
type="radio"
value="option3"
ng-model="disabledChoice"
/>
<label for="disabled-3" class="radio-plain-label"> Option 3 </label>
</div>
</fieldset>
</section>
<section
class="radio-workflow-section"
aria-label="Subscription fieldset"
>
<fieldset class="radio-fieldset field-set">
<legend variant="label">Subscription Plan</legend>
<p>Yearly and lifetime plans offer significant savings.</p>
<div orientation="horizontal" class="field">
<input
id="plan-monthly"
name="subscription"
type="radio"
value="monthly"
ng-model="subscription"
/>
<label for="plan-monthly" class="radio-plain-label">
Monthly ($9.99/month)
</label>
</div>
<div orientation="horizontal" class="field">
<input
id="plan-yearly"
name="subscription"
type="radio"
value="yearly"
ng-model="subscription"
/>
<label for="plan-yearly" class="radio-plain-label">
Yearly ($99.99/year)
</label>
</div>
<div orientation="horizontal" class="field">
<input
id="plan-lifetime"
name="subscription"
type="radio"
value="lifetime"
ng-model="subscription"
/>
<label for="plan-lifetime" class="radio-plain-label">
Lifetime ($299.99)
</label>
</div>
</fieldset>
</section>
<section class="radio-workflow-section" aria-label="Invalid radio group">
<fieldset class="radio-fieldset field-set">
<legend variant="label">Notification Preferences</legend>
<p>Choose how you want to receive notifications.</p>
<div orientation="horizontal" class="field">
<input
id="invalid-email"
name="notification"
type="radio"
value="email"
aria-invalid="true"
ng-model="notification"
/>
<label for="invalid-email" class="radio-plain-label">
Email only
</label>
</div>
<div orientation="horizontal" class="field">
<input
id="invalid-sms"
name="notification"
type="radio"
value="sms"
aria-invalid="true"
ng-model="notification"
/>
<label for="invalid-sms" class="radio-plain-label">
SMS only
</label>
</div>
<div orientation="horizontal" class="field">
<input
id="invalid-both"
name="notification"
type="radio"
value="both"
aria-invalid="true"
ng-model="notification"
/>
<label for="invalid-both" class="radio-plain-label">
Both Email & SMS
</label>
</div>
</fieldset>
</section>
<section
class="radio-workflow-section"
aria-label="RTL density options"
dir="rtl"
lang="ar"
>
<fieldset class="radio-description-list" dir="rtl">
<div orientation="horizontal" class="field">
<input
id="r1-rtl"
name="rtl-density"
type="radio"
value="default"
dir="rtl"
ng-model="rtlDensity"
/>
<section>
<label for="r1-rtl" dir="rtl">افتراضي</label>
<p dir="rtl">تباعد قياسي لمعظم حالات الاستخدام.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="r2-rtl"
name="rtl-density"
type="radio"
value="comfortable"
dir="rtl"
ng-model="rtlDensity"
/>
<section>
<label for="r2-rtl" dir="rtl">مريح</label>
<p dir="rtl">مساحة أكبر بين العناصر.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="r3-rtl"
name="rtl-density"
type="radio"
value="compact"
dir="rtl"
ng-model="rtlDensity"
/>
<section>
<label for="r3-rtl" dir="rtl">مضغوط</label>
<p dir="rtl">تباعد أدنى للتخطيطات الكثيفة.</p>
</section>
</div>
</fieldset>
</section>
</main>
</body>
</html>
Field Compositions
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Radio Fields</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="radioFields={subscription:'free',battery:'',security:'',unlock:'',invalid:'',disabled:''}"
data-example="radio-fields"
>
<main class="radio-fields-demo visual-example field-group">
<fieldset class="field-set">
<legend variant="label" id="subscription-title">
Subscription Plan
</legend>
<div orientation="horizontal" class="field">
<input
id="radio-free"
name="subscription-plan"
type="radio"
value="free"
ng-model="radioFields.subscription"
/>
<label for="radio-free" class="radio-plain-label"> Free Plan </label>
</div>
<div orientation="horizontal" class="field">
<input
id="radio-pro"
name="subscription-plan"
type="radio"
value="pro"
ng-model="radioFields.subscription"
/>
<label for="radio-pro" class="radio-plain-label"> Pro Plan </label>
</div>
<div orientation="horizontal" class="field">
<input
id="radio-enterprise"
name="subscription-plan"
type="radio"
value="enterprise"
ng-model="radioFields.subscription"
/>
<label for="radio-enterprise" class="radio-plain-label">
Enterprise
</label>
</div>
</fieldset>
<fieldset class="field-set" aria-describedby="battery-description">
<legend variant="label" id="battery-title">Battery Level</legend>
<p id="battery-description">Choose your preferred battery level.</p>
<div orientation="horizontal" class="field">
<input
id="battery-high"
name="battery-level"
type="radio"
value="high"
ng-model="radioFields.battery"
/>
<label for="battery-high">High</label>
</div>
<div orientation="horizontal" class="field">
<input
id="battery-medium"
name="battery-level"
type="radio"
value="medium"
ng-model="radioFields.battery"
/>
<label for="battery-medium">Medium</label>
</div>
<div orientation="horizontal" class="field">
<input
id="battery-low"
name="battery-level"
type="radio"
value="low"
ng-model="radioFields.battery"
/>
<label for="battery-low">Low</label>
</div>
</fieldset>
<fieldset class="radio-fields-content-list" aria-label="Device security">
<div orientation="horizontal" class="field">
<input
id="radio-content-1"
name="device-security"
type="radio"
value="touch"
ng-model="radioFields.security"
/>
<section>
<label for="radio-content-1">Enable Touch ID</label>
<p>Enable Touch ID to quickly unlock your device.</p>
</section>
</div>
<div orientation="horizontal" class="field">
<input
id="radio-content-2"
name="device-security"
type="radio"
value="biometric"
ng-model="radioFields.security"
/>
<section>
<label for="radio-content-2">
Enable Touch ID and Face ID to make it even faster to unlock your
device. This is a long label to test the layout.
</label>
<p>Enable Touch ID to quickly unlock your device.</p>
</section>
</div>
</fieldset>
<fieldset class="radio-fields-title-list" aria-label="Device unlock">
<label for="radio-title-1">
<div orientation="horizontal" class="field">
<input
id="radio-title-1"
name="device-unlock"
type="radio"
value="touch"
ng-model="radioFields.unlock"
/>
<span>
<strong>Enable Touch ID</strong>
<small> Enable Touch ID to quickly unlock your device. </small>
</span>
</div>
</label>
<label for="radio-title-2">
<div orientation="horizontal" class="field">
<input
id="radio-title-2"
name="device-unlock"
type="radio"
value="biometric"
ng-model="radioFields.unlock"
/>
<span>
<strong>
Enable Touch ID and Face ID to make it even faster to unlock
your device. This is a long label to test the layout.
</strong>
<small> Enable Touch ID to quickly unlock your device. </small>
</span>
</div>
</label>
</fieldset>
<fieldset class="field-set">
<legend variant="label" id="invalid-title">Invalid Radio Group</legend>
<div orientation="horizontal" class="field">
<input
id="radio-invalid-1"
name="invalid-choice"
type="radio"
value="invalid1"
aria-invalid="true"
ng-model="radioFields.invalid"
/>
<label for="radio-invalid-1"> Invalid Option 1 </label>
</div>
<div orientation="horizontal" class="field">
<input
id="radio-invalid-2"
name="invalid-choice"
type="radio"
value="invalid2"
aria-invalid="true"
ng-model="radioFields.invalid"
/>
<label for="radio-invalid-2"> Invalid Option 2 </label>
</div>
</fieldset>
<fieldset class="field-set" disabled>
<legend variant="label" id="disabled-title">
Disabled Radio Group
</legend>
<div orientation="horizontal" class="field">
<input
id="radio-disabled-1"
name="disabled-choice"
type="radio"
value="disabled1"
ng-model="radioFields.disabled"
/>
<label for="radio-disabled-1"> Disabled Option 1 </label>
</div>
<div orientation="horizontal" class="field">
<input
id="radio-disabled-2"
name="disabled-choice"
type="radio"
value="disabled2"
ng-model="radioFields.disabled"
/>
<label for="radio-disabled-2"> Disabled Option 2 </label>
</div>
</fieldset>
</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 fieldset and radio behavior.
Anatomy
Root styling selector
fieldset:has(input[type="radio"]):not(.toggle-group)
Semantic structure
Use a native fieldset with a legend. Place labeled input type="radio" controls inside it and give related controls the same name. AngularCSS styles the fieldset from that semantic structure.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
checked | Authored | Initial native checked state. |
dir | Authored | Text and interaction direction: ltr or rtl. |
disabled | Authored | Disables native or component interaction. |
name | Authored | Authored HTML attribute or styling hook. |
required | Authored | Marks a native form value as required. |
value | Authored | Native value or authored component value. |
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 fieldset and legend group radio inputs sharing one name. The browser owns selection, arrow-key behavior, disabled state, validation, and form submission; AngularTS ng-model owns application state. AngularCSS registers no radio-group directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use native radio inputs with a shared name and an explicit label for every control. Use fieldset and legend for a visible group label when appropriate. Preserve native disabled and invalid semantics, and connect supporting descriptions with aria-describedby.
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.9 - range
A styled native range input with browser-owned interaction and AngularTS model binding.
Use a native range input directly. AngularCSS adds presentation but registers no
directive.
<label for="volume">Volume</label>
<input id="volume" type="range" min="0" max="100" ng-model="volume" />
<output for="volume">{{ volume }}</output>
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 Range</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="volume = 75"
data-example="slider-demo slider-disabled"
>
<main class="visual-example">
<header>
<label for="volume">Volume</label>
<output for="volume">{{ volume }}</output>
</header>
<input
id="volume"
type="range"
min="0"
max="100"
step="1"
ng-model="volume"
/>
<header>
<label for="volume-disabled">Muted</label>
<output for="volume-disabled">50</output>
</header>
<input
id="volume-disabled"
type="range"
min="0"
max="100"
step="1"
value="50"
disabled
/>
</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 range input behavior and styling.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
disabled | Authored | Disables native or component interaction. |
max | Authored | Maximum native or component value. |
min | Authored | Minimum native or component value. |
orientation | Authored | Layout direction: horizontal or vertical. |
step | Authored | Native numeric step interval. |
value | Authored | Native value or authored component value. |
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
Native range input behavior and styling. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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.10 - scroll-area
A semantic native overflow region with styled scrollbars.
Apply .scroll-area to a bounded semantic region. Add tabindex="0" when the
region should be directly reachable by keyboard.
<section class="scroll-area" tabindex="0" aria-label="Release notes">
<p>Scrollable content goes here.</p>
</section>
The browser owns keyboard, wheel, touch, pointer, RTL, and scrollbar behavior.
AngularTS may add or remove content; native layout updates overflow geometry.
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 Scroll Area</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>
<section
class="scroll-demo scroll-area"
tabindex="0"
aria-label="Release tags"
>
<div class="stack-sm" style="padding: 16px; min-width: 34rem">
<h3>Tags</h3>
<span>v1.2.0-beta.50</span>
<hr />
<span>v1.2.0-beta.49</span>
<hr />
<span>v1.2.0-beta.48</span>
<hr />
<span>v1.2.0-beta.47</span>
<hr />
<span>v1.2.0-beta.46</span>
<hr />
<span>v1.2.0-beta.45</span>
</div>
</section>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Scroll Area 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="showOverflow = false; scrollDirection = 'rtl'"
data-example="scroll-area-demo scroll-area-horizontal-demo scroll-area-rtl"
>
<main class="scroll-area-workflows visual-example">
<section
class="scroll-area-workflow"
aria-labelledby="scroll-tags-heading"
>
<h2 id="scroll-tags-heading">Tags</h2>
<section
class="scroll-area scroll-area-tags"
id="vertical-scroll-area"
tabindex="0"
aria-label="Release tags"
>
<div class="scroll-tag-list">
<span>v1.2.0-beta.50</span>
<hr />
<span>v1.2.0-beta.49</span>
<hr />
<span>v1.2.0-beta.48</span>
<hr />
<span>v1.2.0-beta.47</span>
<hr />
<span>v1.2.0-beta.46</span>
<hr />
<span>v1.2.0-beta.45</span>
<hr />
<span>v1.2.0-beta.44</span>
<hr />
<span>v1.2.0-beta.43</span>
<hr />
<span>v1.2.0-beta.42</span>
<hr />
<span>v1.2.0-beta.41</span>
<hr />
<span>v1.2.0-beta.40</span>
<hr />
<span>v1.2.0-beta.39</span>
</div>
</section>
</section>
<section
class="scroll-area-workflow"
aria-labelledby="scroll-art-heading"
>
<h2 id="scroll-art-heading">Artwork</h2>
<section
class="scroll-area scroll-area-artwork"
id="horizontal-scroll-area"
tabindex="0"
aria-label="Featured artists"
>
<div class="scroll-artwork-row">
<figure>
<img
src="../../images/avatars/01.png"
alt="Portrait by Ornella Binni"
/>
<figcaption>Photo by <strong>Ornella Binni</strong></figcaption>
</figure>
<figure>
<img
src="../../images/avatars/02.png"
alt="Portrait by Tom Byrom"
/>
<figcaption>Photo by <strong>Tom Byrom</strong></figcaption>
</figure>
<figure>
<img
src="../../images/avatars/03.png"
alt="Portrait by Vladimir Malyavko"
/>
<figcaption>
Photo by <strong>Vladimir Malyavko</strong>
</figcaption>
</figure>
<figure>
<img
src="../../images/avatars/04.png"
alt="Portrait by Sarah Chen"
/>
<figcaption>Photo by <strong>Sarah Chen</strong></figcaption>
</figure>
</div>
</section>
</section>
<section
class="scroll-area-workflow"
aria-labelledby="scroll-dynamic-heading"
>
<header>
<h2 id="scroll-dynamic-heading">Dynamic content</h2>
<button
type="button"
variant="outline"
size="sm"
ng-click="showOverflow = !showOverflow"
>
{{ showOverflow ? 'Remove content' : 'Add content' }}
</button>
</header>
<section
class="scroll-area scroll-area-dynamic"
id="dynamic-scroll-area"
tabindex="0"
aria-label="Dynamic release notes"
>
<div class="scroll-dynamic-content">
<p>Current release</p>
<div ng-if="showOverflow" class="scroll-dynamic-overflow">
<p>Compatibility notes</p>
<p>Migration details</p>
<p>API changes</p>
<p>Resolved issues</p>
</div>
</div>
</section>
</section>
<section
class="scroll-area-workflow"
aria-labelledby="scroll-rtl-heading"
dir="rtl"
lang="ar"
>
<header>
<h2 id="scroll-rtl-heading">العلامات</h2>
<button
type="button"
variant="outline"
size="sm"
ng-click="scrollDirection = scrollDirection === 'rtl' ? 'ltr' : 'rtl'"
>
Change direction
</button>
</header>
<section
class="scroll-area scroll-area-tags"
id="rtl-scroll-area"
dir="{{ scrollDirection }}"
tabindex="0"
aria-label="علامات الإصدار"
>
<div class="scroll-tag-list">
<span>v1.2.0-beta.50</span>
<hr />
<span>v1.2.0-beta.49</span>
<hr />
<span>v1.2.0-beta.48</span>
<hr />
<span>v1.2.0-beta.47</span>
<hr />
<span>v1.2.0-beta.46</span>
<hr />
<span>v1.2.0-beta.45</span>
<hr />
<span>v1.2.0-beta.44</span>
<hr />
<span>v1.2.0-beta.43</span>
</div>
</section>
</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 overflow and scrolling.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
dir | Authored | Text and interaction direction: ltr or rtl. |
tabindex | Authored | Use 0 when the overflow region itself must be reachable by keyboard. |
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 focusable semantic region with overflow: auto uses the browser’s native scrolling, keyboard behavior, pointer interaction, direction handling, and scrollbar geometry. AngularTS may insert or remove content; native layout updates the overflow automatically. AngularCSS registers no scroll-area directive.
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.
5.11 - select
Native select styling integrated with AngularTS models and form state.
Use a native select directly and bind application state with AngularTS
ng-model. No wrapper or styling class is required.
<select id="status" ng-model="status" required>
<option value="">Select a status</option>
<option>Todo</option>
<option>Done</option>
</select>
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 Select</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="status=''">
<main class="stack-sm visual-example">
<label for="status">Status</label>
<select id="status" ng-model="status" required>
<option value="">Select a status</option>
<option>Todo</option>
<option>In progress</option>
<option>Done</option>
</select>
<output class="output">Current: {{ status || 'none' }}</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. Native select, option, and optgroup behavior.
Anatomy
Root styling selector
Semantic structure
Use a native select directly. Native option and optgroup elements need no additional attributes. Use AngularTS ng-model, validators, and form directives directly on the select.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
dir | Authored | Text and interaction direction: ltr or rtl. |
disabled | Authored | Disables native or component interaction. |
multiple | Authored | Allows more than one item to remain selected or open. |
name | Authored | Authored HTML attribute or styling hook. |
required | Authored | Marks a native form value as required. |
size | Authored | Visual size token supported by the component stylesheet. |
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
The native select owns values, option groups, keyboard interaction, disabled state, validation, and form submission. AngularTS supplies option registration, ng-model, validators, and form-state classes. AngularCSS registers no select directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a visible label connected by for and id, or provide another accessible name. Preserve native option, optgroup, multiple, disabled, required, invalid, and direction semantics; AngularTS reflects model and validation state without replacing them.
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.12 - separator
Visual and semantic content separator
Use a native hr for a horizontal separator. Add
aria-orientation="vertical" only when it is presented as a vertical divider.
<hr />
<hr aria-orientation="vertical" />
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 Separator</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="separator-demo">
<main class="visual-example">
<section data-example="separator-demo" class="separator-copy-demo">
<div>
<strong>AngularCSS</strong>
<p class="muted">HTML-first styles for enterprise applications</p>
</div>
<hr />
<p>
A set of beautifully designed components that you can customize,
extend, and build on.
</p>
</section>
<section data-example="separator-list" class="separator-list-demo">
<dl>
<dt>Item 1</dt>
<dd>Value 1</dd>
</dl>
<hr />
<dl>
<dt>Item 2</dt>
<dd>Value 2</dd>
</dl>
<hr />
<dl>
<dt>Item 3</dt>
<dd>Value 3</dd>
</dl>
</section>
<section data-example="separator-menu" class="separator-menu-demo">
<div><strong>Settings</strong><span>Manage preferences</span></div>
<hr aria-orientation="vertical" />
<div><strong>Account</strong><span>Profile & security</span></div>
<hr aria-orientation="vertical" />
<div><strong>Help</strong><span>Support & docs</span></div>
</section>
<nav
data-example="separator-vertical"
class="separator-nav-demo"
aria-label="Resource links"
>
<a href="#blog">Blog</a>
<hr aria-orientation="vertical" />
<a href="#docs">Docs</a>
<hr aria-orientation="vertical" />
<a href="#source">Source</a>
</nav>
<section
data-example="separator-rtl"
class="separator-copy-demo"
dir="rtl"
lang="ar"
>
<div>
<strong>AngularCSS</strong>
<p class="muted">الأساس لنظام التصميم الخاص بك</p>
</div>
<hr />
<p>
مجموعة من المكونات المصممة بشكل جميل يمكنك تخصيصها وتوسيعها والبناء
عليها.
</p>
</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 horizontal-rule semantics.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-orientation | Authored | Separator axis: vertical; omit for the native horizontal separator. |
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
Native horizontal-rule semantics. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
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.
5.13 - switch
Toggleable control with semantic switch state attributes.
Use role="switch" on a native checkbox. The browser and AngularTS own its
checked state, validation, and form behavior.
<div orientation="horizontal" class="field">
<input id="airplane-mode" type="checkbox" role="switch" />
<label for="airplane-mode">Airplane mode</label>
</div>
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 Switch</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="mode=false"
data-example="switch-demo"
>
<div class="visual-example">
<input role="switch" id="airplane-mode" type="checkbox" ng-model="mode" />
<label for="airplane-mode">Airplane Mode</label>
<output class="visually-hidden" aria-live="polite">
Mode enabled: <span ng-bind="mode"></span>
</output>
</div>
</body>
</html>
Reference Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Switch 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="small=false; standard=false; share=false; notifications=true; focus=false; terms=false"
data-example="switch-choice-card switch-description switch-disabled switch-invalid switch-rtl switch-sizes"
>
<main class="switch-workflows">
<section class="switch-workflow-section" aria-label="Switch sizes">
<div class="switch-size-list field-group">
<div orientation="horizontal" class="field">
<input
role="switch"
id="switch-size-sm"
type="checkbox"
size="sm"
ng-model="small"
/>
<label for="switch-size-sm">Small</label>
</div>
<div orientation="horizontal" class="field">
<input
role="switch"
id="switch-size-default"
type="checkbox"
size="default"
ng-model="standard"
/>
<label for="switch-size-default">Default</label>
</div>
</div>
</section>
<section class="switch-workflow-section" aria-label="Disabled switch">
<div orientation="horizontal" class="field">
<input
role="switch"
id="switch-disabled-unchecked"
type="checkbox"
disabled
/>
<label for="switch-disabled-unchecked">Disabled</label>
</div>
</section>
<section class="switch-workflow-section" aria-label="Switch description">
<div orientation="horizontal" class="field">
<section>
<label for="switch-focus-mode">Share across devices</label>
<p>
Focus is shared across devices, and turns off when you leave the
app.
</p>
</section>
<input
role="switch"
id="switch-focus-mode"
type="checkbox"
ng-model="focus"
/>
</div>
</section>
<section class="switch-workflow-section" aria-label="Invalid switch">
<div orientation="horizontal" class="field">
<section>
<label for="switch-terms"> Accept terms and conditions </label>
<p>You must accept the terms and conditions to continue.</p>
</section>
<input
role="switch"
id="switch-terms"
type="checkbox"
aria-invalid="true"
ng-model="terms"
/>
</div>
</section>
<section
class="switch-workflow-section switch-workflow-wide"
aria-label="Switch choice cards"
>
<div class="switch-choice-list field-group">
<label for="switch-share" class="switch-choice">
<div orientation="horizontal" class="field">
<span>
<strong>Share across devices</strong>
<small>
Focus is shared across devices, and turns off when you leave
the app.
</small>
</span>
<input
role="switch"
id="switch-share"
type="checkbox"
ng-model="share"
/>
</div>
</label>
<label for="switch-notifications" class="switch-choice">
<div orientation="horizontal" class="field">
<span>
<strong>Enable notifications</strong>
<small>
Receive notifications when focus mode is enabled or disabled.
</small>
</span>
<input
role="switch"
id="switch-notifications"
type="checkbox"
ng-model="notifications"
/>
</div>
</label>
</div>
</section>
<section
class="switch-workflow-section switch-workflow-wide"
aria-label="RTL switch"
dir="rtl"
lang="ar"
>
<div orientation="horizontal" class="field">
<section>
<label for="switch-focus-mode-rtl"> المشاركة عبر الأجهزة </label>
<p>
يتم مشاركة التركيز عبر الأجهزة، ويتم إيقاف تشغيله عند مغادرة
التطبيق.
</p>
</section>
<input
role="switch"
id="switch-focus-mode-rtl"
type="checkbox"
dir="rtl"
/>
</div>
</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 checkbox state with switch presentation.
Anatomy
Root styling selector
input[type="checkbox"][role="switch"]
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
checked | Authored | Initial native checked state. |
disabled | Authored | Disables native or component interaction. |
required | Authored | Marks a native form value as required. |
role | Authored | Explicit semantic role when native HTML does not provide one. |
size | Authored | Switch size: sm; omit for the default size. |
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
Native checkbox state with switch presentation. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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.14 - table
Semantic data table
Use a native table inside a figure. AngularCSS styles its semantic table
structure directly.
<figure>
<table>
<thead>
<tr>
<th scope="col">Invoice</th>
</tr>
</thead>
</table>
</figure>
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 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>
<figure>
<table>
<caption>
A list of recent invoices.
</caption>
<thead>
<tr>
<th scope="col">Invoice</th>
<th scope="col">Status</th>
<th scope="col">Method</th>
<th class="text-right" scope="col">Amount</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">INV001</th>
<td>Paid</td>
<td>Card</td>
<td class="text-right">$250.00</td>
</tr>
<tr>
<th scope="row">INV002</th>
<td>Pending</td>
<td>PayPal</td>
<td class="text-right">$150.00</td>
</tr>
<tr>
<th scope="row">INV003</th>
<td>Unpaid</td>
<td>Transfer</td>
<td class="text-right">$350.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Total</td>
<td class="text-right">$750.00</td>
</tr>
</tfoot>
</table>
</figure>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Table 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="invoices=[{id:'INV001',status:'Paid',method:'Credit Card',amount:'$250.00'},{id:'INV002',status:'Pending',method:'PayPal',amount:'$150.00'},{id:'INV003',status:'Unpaid',method:'Bank Transfer',amount:'$350.00'},{id:'INV004',status:'Paid',method:'Credit Card',amount:'$450.00'},{id:'INV005',status:'Paid',method:'PayPal',amount:'$550.00'},{id:'INV006',status:'Pending',method:'Bank Transfer',amount:'$200.00'},{id:'INV007',status:'Unpaid',method:'Credit Card',amount:'$300.00'}];products=[{name:'Wireless Mouse',price:'$29.99'},{name:'Mechanical Keyboard',price:'$129.99'},{name:'USB-C Hub',price:'$49.99'}];payments=[{id:'m5gr84i9',amount:'$316.00',status:'success',statusAr:'ناجح',email:'ken99@example.com',selected:false},{id:'3u1reuv4',amount:'$242.00',status:'success',statusAr:'ناجح',email:'Abe45@example.com',selected:false},{id:'derv1ws0',amount:'$837.00',status:'processing',statusAr:'قيد المعالجة',email:'Monserrat44@example.com',selected:false},{id:'5kma53ae',amount:'$874.00',status:'success',statusAr:'ناجح',email:'Silas22@example.com',selected:false},{id:'bhqecj4p',amount:'$721.00',status:'failed',statusAr:'فشل',email:'carmella@example.com',selected:false}];dataState={query:'',order:'email',all:false,selected:0,showStatus:true,showEmail:true,showAmount:true};rtlDataState={query:'',order:'email',all:false,showStatus:true,showEmail:true,showAmount:true};tableState={action:'Ready'}"
>
<main class="table-workflow-grid" aria-label="Table workflows">
<section
class="table-workflow table-workflow-wide"
data-example="table-demo table-footer"
aria-label="Recent invoices"
>
<figure>
<table>
<caption>
A list of your recent invoices.
</caption>
<thead>
<tr>
<th scope="col">Invoice</th>
<th scope="col">Status</th>
<th scope="col">Method</th>
<th scope="col" class="text-right">Amount</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="invoice in invoices" animate>
<th scope="row">{{ invoice.id }}</th>
<td>{{ invoice.status }}</td>
<td>{{ invoice.method }}</td>
<td class="text-right">{{ invoice.amount }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Total</td>
<td class="text-right">$2,500.00</td>
</tr>
</tfoot>
</table>
</figure>
</section>
<section
class="table-workflow table-actions-example"
data-example="table-actions"
aria-label="Product actions"
>
<figure>
<table>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col">Price</th>
<th scope="col" class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products" animate>
<th scope="row">{{ product.name }}</th>
<td>{{ product.price }}</td>
<td class="text-right">
<div ng-dropdown-menu class="table-action-menu">
<button
variant="ghost"
size="icon-xs"
type="button"
aria-label="Open menu for {{ product.name }}"
>
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="5" cy="12" r="1"></circle>
<circle cx="12" cy="12" r="1"></circle>
<circle cx="19" cy="12" r="1"></circle>
</svg>
</button>
<menu>
<button ng-click="tableState.action='Edit '+product.name">
Edit
</button>
<button
ng-click="tableState.action='Duplicate '+product.name"
>
Duplicate
</button>
<hr />
<button
variant="destructive"
ng-click="tableState.action='Delete '+product.name"
>
Delete
</button>
</menu>
</div>
</td>
</tr>
</tbody>
</table>
</figure>
</section>
<section
class="table-workflow"
data-example="table-rtl"
aria-label="جدول الفواتير"
dir="rtl"
lang="ar"
>
<figure>
<table>
<caption>
قائمة بفواتيرك الأخيرة.
</caption>
<thead>
<tr>
<th scope="col">الفاتورة</th>
<th scope="col">الحالة</th>
<th scope="col">الطريقة</th>
<th scope="col" class="text-start">المبلغ</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">INV001</th>
<td>مدفوع</td>
<td>بطاقة ائتمانية</td>
<td>$250.00</td>
</tr>
<tr>
<th scope="row">INV002</th>
<td>قيد الانتظار</td>
<td>PayPal</td>
<td>$150.00</td>
</tr>
<tr>
<th scope="row">INV003</th>
<td>غير مدفوع</td>
<td>تحويل بنكي</td>
<td>$350.00</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">المجموع</td>
<td>$2,500.00</td>
</tr>
</tfoot>
</table>
</figure>
</section>
<section
class="table-workflow table-workflow-wide"
data-example="data-table-demo"
aria-label="Payments data table"
>
<div class="data-table-toolbar">
<input
ng-model="dataState.query"
placeholder="Filter emails..."
aria-label="Filter payment emails"
/>
<div ng-dropdown-menu>
<button variant="outline" type="button">
Columns <span aria-hidden="true">⌄</span>
</button>
<menu>
<button
aria-checked="{{ dataState.showStatus }}"
ng-click="dataState.showStatus=!dataState.showStatus"
>
Status
</button>
<button
aria-checked="{{ dataState.showEmail }}"
ng-click="dataState.showEmail=!dataState.showEmail"
>
Email
</button>
<button
aria-checked="{{ dataState.showAmount }}"
ng-click="dataState.showAmount=!dataState.showAmount"
>
Amount
</button>
</menu>
</div>
</div>
<figure class="data-table-frame">
<table>
<thead>
<tr>
<th scope="col" class="data-table-select">
<input
type="checkbox"
ng-model="dataState.all"
ng-change="payments[0].selected=dataState.all;payments[1].selected=dataState.all;payments[2].selected=dataState.all;payments[3].selected=dataState.all;payments[4].selected=dataState.all"
aria-label="Select all payments"
/>
</th>
<th scope="col" ng-if="dataState.showStatus">Status</th>
<th scope="col" ng-if="dataState.showEmail">
<button
variant="ghost"
type="button"
ng-click="dataState.order=dataState.order==='email' ? '-email' : 'email'"
>
Email <span aria-hidden="true">↕</span>
</button>
</th>
<th scope="col" ng-if="dataState.showAmount" class="text-right">
Amount
</th>
<th scope="col">
<span class="visually-hidden">Actions</span>
</th>
</tr>
</thead>
<tbody>
<tr
ng-repeat="payment in payments | filter:dataState.query | orderBy:dataState.order"
animate
aria-selected="{{ payment.selected }}"
>
<td class="data-table-select">
<input
type="checkbox"
ng-model="payment.selected"
ng-change="dataState.selected=payment.selected ? 1 : 0"
aria-label="Select {{ payment.email }}"
/>
</td>
<td ng-if="dataState.showStatus" class="capitalize">
{{ payment.status }}
</td>
<td ng-if="dataState.showEmail" class="lowercase">
{{ payment.email }}
</td>
<td
ng-if="dataState.showAmount"
class="text-right table-cell-medium"
>
{{ payment.amount }}
</td>
<td class="text-right">
<button
variant="ghost"
size="icon-xs"
type="button"
ng-click="tableState.action='Open '+payment.id"
aria-label="Open menu for {{ payment.email }}"
>
•••
</button>
</td>
</tr>
<tr ng-if="!(payments | filter:dataState.query).length" animate>
<td colspan="5" class="data-table-empty">No results.</td>
</tr>
</tbody>
</table>
</figure>
<div class="data-table-footer">
<p>{{ dataState.selected }} of 5 row(s) selected.</p>
<div class="row">
<button variant="outline" size="sm" type="button" disabled>
Previous</button
><button variant="outline" size="sm" type="button" disabled>
Next
</button>
</div>
</div>
</section>
<section
class="table-workflow table-workflow-wide"
data-example="data-table-rtl"
aria-label="جدول بيانات المدفوعات"
dir="rtl"
lang="ar"
ng-init="rtlPayments=[{amount:'$316.00',statusAr:'ناجح',email:'ken99@example.com',selected:false},{amount:'$242.00',statusAr:'ناجح',email:'Abe45@example.com',selected:false},{amount:'$837.00',statusAr:'قيد المعالجة',email:'Monserrat44@example.com',selected:false},{amount:'$874.00',statusAr:'ناجح',email:'Silas22@example.com',selected:false},{amount:'$721.00',statusAr:'فشل',email:'carmella@example.com',selected:false}]"
>
<div class="data-table-toolbar">
<input
ng-model="rtlDataState.query"
placeholder="تصفية البريد الإلكتروني..."
aria-label="تصفية البريد الإلكتروني"
/>
<div ng-dropdown-menu>
<button variant="outline" type="button">
الأعمدة <span aria-hidden="true">⌄</span>
</button>
<menu>
<button
aria-checked="{{ rtlDataState.showStatus }}"
ng-click="rtlDataState.showStatus=!rtlDataState.showStatus"
>
الحالة
</button>
<button
aria-checked="{{ rtlDataState.showEmail }}"
ng-click="rtlDataState.showEmail=!rtlDataState.showEmail"
>
البريد الإلكتروني
</button>
<button
aria-checked="{{ rtlDataState.showAmount }}"
ng-click="rtlDataState.showAmount=!rtlDataState.showAmount"
>
المبلغ
</button>
</menu>
</div>
</div>
<figure class="data-table-frame">
<table>
<thead>
<tr>
<th scope="col" class="data-table-select">
<input
type="checkbox"
ng-model="rtlDataState.all"
aria-label="تحديد الكل"
/>
</th>
<th scope="col" ng-if="rtlDataState.showStatus">الحالة</th>
<th scope="col" ng-if="rtlDataState.showEmail">
<button
variant="ghost"
type="button"
ng-click="rtlDataState.order=rtlDataState.order==='email' ? '-email' : 'email'"
>
البريد الإلكتروني <span aria-hidden="true">↕</span>
</button>
</th>
<th scope="col" ng-if="rtlDataState.showAmount">المبلغ</th>
<th scope="col">
<span class="visually-hidden">الإجراءات</span>
</th>
</tr>
</thead>
<tbody>
<tr
ng-repeat="payment in rtlPayments | filter:rtlDataState.query | orderBy:rtlDataState.order"
animate
>
<td class="data-table-select">
<input
type="checkbox"
ng-model="payment.selected"
aria-label="تحديد {{ payment.email }}"
/>
</td>
<td ng-if="rtlDataState.showStatus">{{ payment.statusAr }}</td>
<td ng-if="rtlDataState.showEmail" class="lowercase">
{{ payment.email }}
</td>
<td ng-if="rtlDataState.showAmount" class="table-cell-medium">
{{ payment.amount }}
</td>
<td>
<button
variant="ghost"
size="icon-xs"
type="button"
aria-label="فتح القائمة"
>
•••
</button>
</td>
</tr>
<tr
ng-if="!(rtlPayments | filter:rtlDataState.query).length"
animate
>
<td colspan="5" class="data-table-empty">لا توجد نتائج.</td>
</tr>
</tbody>
</table>
</figure>
<div class="data-table-footer">
<p>0 من 5 صف(وف) محدد.</p>
<div class="row">
<button variant="outline" size="sm" type="button" disabled>
السابق</button
><button variant="outline" size="sm" type="button" disabled>
التالي
</button>
</div>
</div>
</section>
<output class="table-workflow-output">{{ tableState.action }}</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. Native tabular structure and header scopes.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-selected | Authored | Selected item state. |
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
Native tabular structure and header scopes. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Keep meaningful labels and table or figure structure in authored HTML. Do not rely on color, position, or generated visual marks as the only representation of data.
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.15 - textarea
Multi-line text control with state attributes for empty/required/disabled/error.
Use native textarea controls; AngularCSS styles them directly.
<textarea placeholder="Add a message"></textarea>
<textarea placeholder="Invalid" aria-invalid="true"></textarea>
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 Textarea</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="message='Ship semantic components';rtlMessage='';textareaAction='Ready'"
data-example="textarea-button textarea-demo textarea-disabled textarea-field textarea-invalid textarea-rtl"
>
<main class="visual-example">
<div class="field">
<label for="docs-textarea-message">Message</label>
<textarea
id="docs-textarea-message"
placeholder="Add a message"
ng-model="message"
></textarea>
<p>Add context for your request.</p>
</div>
<div class="field">
<label for="docs-textarea-disabled">Disabled</label>
<textarea
id="docs-textarea-disabled"
placeholder="Disabled"
disabled
></textarea>
</div>
<div class="field">
<label for="docs-textarea-invalid">Invalid</label>
<textarea
id="docs-textarea-invalid"
placeholder="Invalid"
aria-invalid="true"
></textarea>
<p class="field-error">A message is required.</p>
</div>
<div class="textarea-button-demo field">
<label for="docs-textarea-reply">Reply</label>
<textarea
id="docs-textarea-reply"
placeholder="Type your message here."
></textarea>
<button type="button" ng-click="textareaAction='Message sent'">
Send message
</button>
</div>
<div dir="rtl" lang="ar" class="field">
<label for="docs-textarea-rtl">رسالتك</label>
<textarea
id="docs-textarea-rtl"
ng-model="rtlMessage"
placeholder="اكتب رسالتك هنا."
></textarea>
<p>سيتم إرسال رد إلى بريدك الإلكتروني.</p>
</div>
<output class="output textarea-output">
Message: {{ message ? message : "empty" }} · {{ textareaAction }}
</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. Native textarea behavior and AngularTS models.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
disabled | Authored | Disables native or component interaction. |
required | Authored | Marks a native form value as required. |
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
Native textarea behavior and AngularTS models. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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 - Patterns
Small semantic HTML compositions built from native elements and CSS.
6.1 - accordion
Expandable content sections
Use an accessibly named section around native details elements. Give
sibling items the same name when opening one item should close the others.
The semantic structure needs no component class.
<section aria-label="Sections">
<details name="sections" open>
<summary>Section 1</summary>
<div>Content for section 1</div>
</details>
</section>
Omit name to allow more than one section to remain open.
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 Accordion</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="accordion-demo">
<section class="visual-example" aria-label="Shipping questions">
<details name="shipping-questions" open>
<summary>What are your shipping options?</summary>
<div>
We offer standard (5-7 days), express (2-3 days), and overnight
shipping. Free shipping on international orders.
</div>
</details>
<details name="shipping-questions">
<summary>What is your return policy?</summary>
<div>
Returns are accepted within 30 days. Items must be unused and in their
original packaging.
</div>
</details>
<details name="shipping-questions">
<summary>How can I contact customer support?</summary>
<div>Reach us by email, live chat, or phone during business hours.</div>
</details>
</section>
</body>
</html>
State Variants
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Accordion State 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="accordion-basic accordion-disabled accordion-multiple"
>
<main class="accordion-workflow-grid">
<section
class="accordion-workflow-section"
aria-labelledby="accordion-basic-title"
>
<h2 id="accordion-basic-title">Account help</h2>
<section aria-label="Account help questions">
<details name="account-help" open>
<summary>How do I reset my password?</summary>
<div>
Click Forgot Password on the login page, enter your email address,
and we'll send you a reset link that expires in 24 hours.
</div>
</details>
<details name="account-help">
<summary>Can I change my subscription plan?</summary>
<div>
You can upgrade or downgrade your plan at any time from your
account settings.
</div>
</details>
<details name="account-help">
<summary>What payment methods do you accept?</summary>
<div>We accept major credit cards, PayPal, and bank transfers.</div>
</details>
</section>
</section>
<section
class="accordion-workflow-section"
aria-labelledby="accordion-disabled-title"
>
<h2 id="accordion-disabled-title">Availability</h2>
<section aria-label="Feature availability questions">
<details name="availability">
<summary>Can I access my account history?</summary>
<div>
Your complete account history is available from the dashboard.
</div>
</details>
<details name="availability" inert>
<summary>Premium feature information</summary>
<div>Upgrade your plan to access premium feature information.</div>
</details>
<details name="availability">
<summary>How do I update my email address?</summary>
<div>
Update it in account settings and confirm the verification email.
</div>
</details>
</section>
</section>
<section
class="accordion-workflow-section accordion-workflow-wide"
aria-labelledby="accordion-multiple-title"
>
<h2 id="accordion-multiple-title">Settings</h2>
<section aria-label="Settings questions">
<details open>
<summary>Notification Settings</summary>
<div>
Choose email alerts or push notifications for mobile devices.
</div>
</details>
<details>
<summary>Privacy & Security</summary>
<div>
Enable two-factor authentication, review active sessions, and
configure data sharing.
</div>
</details>
<details>
<summary>Billing & Subscription</summary>
<div>View your plan, payment history, and upcoming invoices.</div>
</details>
</section>
</section>
</main>
</body>
</html>
Layout Variants
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Accordion Layout 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="accordion-borders accordion-card accordion-rtl"
>
<main class="accordion-workflow-grid accordion-layout-workflows">
<section
class="accordion-workflow-section"
aria-labelledby="accordion-borders-title"
>
<h2 id="accordion-borders-title">Billing questions</h2>
<section class="accordion-bordered" aria-label="Billing questions">
<details name="billing" open>
<summary>How does billing work?</summary>
<div>
Billing is charged at the beginning of each monthly or annual
cycle, and you can cancel anytime.
</div>
</details>
<details name="billing">
<summary>Is my data secure?</summary>
<div>
Data is encrypted at rest and in transit using industry-standard
protocols.
</div>
</details>
<details name="billing">
<summary>What integrations do you support?</summary>
<div>
Connect popular tools or build custom integrations with our API.
</div>
</details>
</section>
</section>
<article
class="accordion-card-demo card"
aria-labelledby="accordion-card-title"
>
<header>
<h2 id="accordion-card-title">Subscription & Billing</h2>
<p>Common questions about plans, payments, and cancellations.</p>
</header>
<section>
<section aria-label="Subscription and billing questions">
<details name="subscription" open>
<summary>What subscription plans do you offer?</summary>
<div>
Choose Starter, Professional, or Enterprise based on storage,
API, and support needs.
</div>
</details>
<details name="subscription">
<summary>How does billing work?</summary>
<div>
Billing occurs automatically at the start of each cycle.
</div>
</details>
<details name="subscription">
<summary>How do I cancel my subscription?</summary>
<div>
Cancel from account settings with access through the current
billing period.
</div>
</details>
</section>
</section>
</article>
<section
class="accordion-workflow-section accordion-workflow-wide"
dir="rtl"
lang="ar"
aria-labelledby="accordion-rtl-title"
>
<h2 id="accordion-rtl-title">الأسئلة الشائعة</h2>
<section aria-label="الأسئلة الشائعة">
<details name="arabic-faq" open>
<summary>كيف يمكنني إعادة تعيين كلمة المرور؟</summary>
<div>
انقر على نسيت كلمة المرور في صفحة تسجيل الدخول، وسنرسل لك رابطًا
لإعادة تعيينها.
</div>
</details>
<details name="arabic-faq">
<summary>هل يمكنني تغيير خطة الاشتراك الخاصة بي؟</summary>
<div>يمكنك ترقية خطتك أو تخفيضها في أي وقت من إعدادات الحساب.</div>
</details>
<details name="arabic-faq">
<summary>ما هي طرق الدفع التي تقبلونها؟</summary>
<div>نقبل بطاقات الائتمان وPayPal والتحويلات المصرفية.</div>
</details>
</section>
</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. Named native details disclosures.
Anatomy
Root styling selector
section[aria-label]:has(> details)
Semantic structure
Use an accessibly named section around direct details children. Each item requires a direct summary followed by authored content. Apply the same name to sibling details for exclusive disclosure.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
inert | Authored | Prevents interaction while the component is hidden. |
name | Authored | Authored HTML attribute or styling hook. |
open | Authored | Initial or controlled open state. |
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
Native details and summary own disclosure, focus, and keyboard behavior. Give sibling details the same name for an exclusive accordion, or omit name when several panels may remain open. AngularCSS registers no accordion directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a direct summary as the accessible trigger for each details item. The browser exposes disclosure state and keyboard activation. Use inert only when an entire unavailable disclosure must be removed from interaction.
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.2 - alert
Compact feedback blocks for status and context.
Use section[role="alert"] for important feedback blocks. The default presentation is
neutral; add variant="destructive" for destructive feedback or override the
AngularCSS color tokens for application-specific colors.
<section role="alert">
<svg aria-hidden="true"><!-- optional icon --></svg>
<h2>Saved!</h2>
<p>Your profile was updated.</p>
<div>
<button ng-click="dismiss()">Dismiss</button>
</div>
</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</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-demo">
<div class="visual-example">
<section aria-live="assertive" aria-atomic="true" role="alert">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M9 12l2 2 4-4"></path>
</svg>
<h2>Payment successful</h2>
<p>
Your payment of $29.99 has been processed. A receipt has been sent to
your email address.
</p>
</section>
<section aria-live="assertive" aria-atomic="true" role="alert">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4" />
<path d="M12 8h.01" />
</svg>
<h2>New feature available</h2>
<p>
We've added dark mode support. You can enable it in your account
settings.
</p>
</section>
</div>
</body>
</html>
Variants 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 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="darkModeEnabled=false"
data-example="alert-action alert-basic alert-colors alert-destructive alert-rtl"
>
<main class="alert-workflow-grid">
<section role="alert">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none">
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="2"
/>
<path
d="m9 12 2 2 4-4"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<h2>Account updated successfully</h2>
<p>
Your profile information has been saved. Changes will be reflected
immediately.
</p>
</section>
<section aria-live="polite" role="alert">
<h2>Dark mode is now available</h2>
<p>Enable it under your profile settings to get started.</p>
<button
size="xs"
type="button"
ng-click="darkModeEnabled=true"
ng-disabled="darkModeEnabled"
>
{{ darkModeEnabled ? 'Enabled' : 'Enable' }}
</button>
</section>
<section variant="warning" role="alert">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none">
<path
d="M10.3 2.9 1.8 17a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 2.9a2 2 0 0 0-3.4 0Z"
stroke="currentColor"
stroke-width="2"
stroke-linejoin="round"
/>
<path
d="M12 9v4M12 17h.01"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<h2>Your subscription will expire in 3 days.</h2>
<p>
Renew now to avoid service interruption or upgrade to a paid plan.
</p>
</section>
<section variant="destructive" role="alert">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none">
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="2"
/>
<path
d="M12 8v4M12 16h.01"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<h2>Payment failed</h2>
<p>
Your payment could not be processed. Check your payment method and try
again.
</p>
</section>
<section
class="alert-rtl-demo"
dir="rtl"
lang="ar"
aria-label="التنبيهات"
>
<section role="alert">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none">
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="2"
/>
<path
d="m9 12 2 2 4-4"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<h2>تم الدفع بنجاح</h2>
<p>تمت معالجة دفعتك وإرسال إيصال إلى عنوان بريدك الإلكتروني.</p>
</section>
<section role="alert">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none">
<circle
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="2"
/>
<path
d="M12 16v-4M12 8h.01"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<h2>ميزة جديدة متاحة</h2>
<p>لقد أضفنا دعم الوضع الداكن ويمكنك تفعيله في إعدادات حسابك.</p>
</section>
</section>
<output class="output alert-workflow-output">
Dark mode: {{ darkModeEnabled ? 'enabled' : 'disabled' }}
</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. Semantic authored status content.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-atomic | Authored | Whether an assistive technology announces the entire updated region. |
aria-live | Authored | Announcement priority for updates to a live region. |
role | Authored | Explicit semantic role when native HTML does not provide one. |
variant | Authored | Status presentation: info, success, warning, or destructive; omit for the default presentation. |
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
Semantic authored status content. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use the appropriate live-region or status semantics for dynamic feedback. Decorative feedback must stay hidden from assistive technology.
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.3 - aspect-ratio
Fixed-ratio media wrapper
Set ratio on a figure and optionally override --ratio. Direct images,
videos, and iframes fill the figure with object-fit: cover; applications may
override that fit when media should not crop.
<figure ratio="16 / 9">
<img src="photo.jpg" alt="Photo" />
</figure>
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 Aspect Ratio</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="aspect-ratio-demo">
<figure ratio="16 / 9" class="visual-example">
<img src="../../images/avatars/01.png" alt="Photo" />
</figure>
</body>
</html>
Ratios And Direction
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Aspect Ratio 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="aspect-ratio-portrait aspect-ratio-rtl aspect-ratio-square"
>
<main class="aspect-ratio-workflows">
<figure
ratio="9 / 16"
class="aspect-ratio-portrait"
aria-label="Portrait aspect ratio"
>
<img src="../../images/avatars/01.png" alt="Photo" />
</figure>
<figure
ratio="1 / 1"
class="aspect-ratio-square"
aria-label="Square aspect ratio"
>
<img src="../../images/avatars/01.png" alt="Photo" />
</figure>
<figure class="aspect-ratio-rtl" dir="rtl" lang="ar">
<figure ratio="16 / 9" aria-label="Landscape aspect ratio">
<img src="../../images/avatars/01.png" alt="صورة" />
</figure>
<figcaption>منظر طبيعي جميل</figcaption>
</figure>
</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. CSS aspect-ratio layout.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
ratio | Authored | Aspect ratio: 1 / 1, 9 / 16, or 16 / 9; defaults to 16 / 9. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|
--ratio | Rendered aspect ratio; defaults to 16 / 9. |
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
CSS aspect-ratio layout. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
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.
6.4 - avatar
User avatar, fallback, badge, and group primitives.
Use .avatar with a native image or authored fallback, plus an optional badge.
Place adjacent avatars and a native output in one wrapper to form a group.
<span class="avatar" aria-label="Jane Doe">
<span>JD</span>
<output></output>
</span>
<span>
<span class="avatar"><img src="avatar.jpg" alt="Alex Brown" /></span>
<output>+3</output>
</span>
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 Avatar</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="avatar-badge avatar-basic avatar-demo avatar-group avatar-group-count"
>
<div class="visual-example">
<span class="avatar">
<img
class="avatar-grayscale"
src="../../images/avatars/01.png"
alt="Profile portrait"
/>
<span>CN</span>
</span>
<span class="avatar">
<img src="../../images/avatars/02.png" alt="Profile portrait" />
<span>ER</span>
<output variant="success"></output>
</span>
<span class="avatar" aria-label="Jane Doe">
<span>JD</span>
</span>
<span class="avatar-grayscale">
<span class="avatar">
<img src="../../images/avatars/01.png" alt="Profile portrait" />
<span>CN</span>
</span>
<span class="avatar">
<img src="../../images/avatars/03.png" alt="Profile portrait" />
<span>LR</span>
</span>
<span class="avatar">
<img src="../../images/avatars/04.png" alt="Profile portrait" />
<span>ER</span>
</span>
<output>+3</output>
</span>
</div>
</body>
</html>
Variants And Composition
Use size="sm", the default size, or size="lg". Badge icons, grouped counts,
RTL layouts, and dropdown triggers compose from the same semantic parts without
changing Avatar 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 Avatar 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="avatarAction = 'None'"
data-example="avatar-badge-icon avatar-dropdown avatar-group-count-icon avatar-rtl avatar-size"
>
<main class="avatar-workflows">
<section
class="avatar-workflow-section"
aria-labelledby="avatar-badge-heading"
>
<h2 id="avatar-badge-heading">Badge icon</h2>
<div class="avatar-workflow-row" aria-label="Avatar badge icon">
<span class="avatar">
<img
class="avatar-grayscale"
src="../../images/avatars/02.png"
alt="@pranathip"
/>
<span>PP</span>
<output>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
aria-hidden="true"
>
<path d="M5 12h14" />
<path d="M12 5v14" />
</svg>
</output>
</span>
</div>
</section>
<section
class="avatar-workflow-section"
aria-labelledby="avatar-count-heading"
>
<h2 id="avatar-count-heading">Group count icon</h2>
<div class="avatar-grayscale" aria-label="Avatar group count icon">
<span class="avatar">
<img src="../../images/avatars/01.png" alt="@angularcss" />
<span>CN</span>
</span>
<span class="avatar">
<img src="../../images/avatars/03.png" alt="@maxleiter" />
<span>LR</span>
</span>
<span class="avatar">
<img src="../../images/avatars/04.png" alt="@evilrabbit" />
<span>ER</span>
</span>
<output>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
aria-hidden="true"
>
<path d="M5 12h14" />
<path d="M12 5v14" />
</svg>
</output>
</div>
</section>
<section
class="avatar-workflow-section"
aria-labelledby="avatar-size-heading"
>
<h2 id="avatar-size-heading">Sizes</h2>
<div
class="avatar-workflow-row avatar-grayscale"
aria-label="Avatar sizes"
>
<span size="sm" class="avatar">
<img src="../../images/avatars/01.png" alt="@angularcss small" />
<span>CN</span>
</span>
<span class="avatar">
<img src="../../images/avatars/01.png" alt="@angularcss default" />
<span>CN</span>
</span>
<span size="lg" class="avatar">
<img src="../../images/avatars/01.png" alt="@angularcss large" />
<span>CN</span>
</span>
</div>
</section>
<section
class="avatar-workflow-section avatar-dropdown-stage"
aria-labelledby="avatar-menu-heading"
>
<h2 id="avatar-menu-heading">Dropdown</h2>
<div ng-dropdown-menu>
<button
type="button"
variant="ghost"
size="icon"
class="avatar-dropdown-trigger"
aria-label="Open user menu"
>
<span class="avatar">
<img src="../../images/avatars/01.png" alt="AngularCSS" />
<span>CN</span>
</span>
</button>
<menu style="--menu-width: 8rem">
<section>
<button ng-click="avatarAction = 'Profile'">Profile</button>
<button ng-click="avatarAction = 'Billing'">Billing</button>
<button ng-click="avatarAction = 'Settings'">Settings</button>
</section>
<hr />
<section>
<button variant="destructive" ng-click="avatarAction = 'Log out'">
Log out
</button>
</section>
</menu>
</div>
<output class="avatar-workflow-output">
Selected: {{ avatarAction }}
</output>
</section>
<section
class="avatar-workflow-section avatar-workflow-wide"
aria-labelledby="avatar-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="avatar-rtl-heading">اتجاه من اليمين إلى اليسار</h2>
<div
class="avatar-workflow-row avatar-rtl-demo"
aria-label="صور رمزية من اليمين إلى اليسار"
>
<span class="avatar">
<img
class="avatar-grayscale"
src="../../images/avatars/01.png"
alt="@angularcss"
/>
<span>CN</span>
</span>
<span class="avatar-rtl-badge avatar">
<img src="../../images/avatars/04.png" alt="@evilrabbit" />
<span>ER</span>
<output variant="success"></output>
</span>
<span class="avatar-grayscale">
<span class="avatar">
<img src="../../images/avatars/01.png" alt="@angularcss" />
<span>CN</span>
</span>
<span class="avatar">
<img src="../../images/avatars/03.png" alt="@maxleiter" />
<span>LR</span>
</span>
<span class="avatar">
<img src="../../images/avatars/04.png" alt="@evilrabbit" />
<span>ER</span>
</span>
<output>+٣</output>
</span>
</div>
</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 image and fallback composition.
Anatomy
Root styling selector
Semantic structure
Apply .avatar to a wrapper containing either an image or authored fallback content. Badges are optional. Place adjacent avatars and a native output for the remaining count in one div or span; AngularCSS recognizes that group from its structure.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
size | Authored | Avatar size: sm or lg; omit for the default size. |
variant | Authored | Optional direct output badge status: success; omit for the primary status color. |
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
Avatar is a styling-only authored HTML pattern. Native img loading and alternative text remain browser behavior; use a fallback-only avatar when no image is available, or AngularTS structural directives when application state chooses between sources.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give meaningful portrait images useful alternative text. Give fallback-only avatars an accessible name when initials are ambiguous, and keep decorative status badges out of repeated announcements.
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.5 - badge
Inline status and metadata labels with semantic variants.
Use class="badge" on an inline element and set variant for appearance.
<span class="badge">Default</span>
<span variant="secondary" class="badge">Secondary</span>
<span variant="outline" class="badge">Outline</span>
For user-selected colors, use variant="custom" and set --badge-background.
Browsers with contrast-color() choose a black or white foreground; set
--badge-foreground when the application requires a specific contrast result.
<span variant="custom" class="badge" style="--badge-background: var(--cyan-9)">
Custom
</span>
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 Badge</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="badge-demo">
<div class="row visual-example">
<span class="badge">Badge</span>
<span variant="secondary" class="badge">Secondary</span>
<span variant="destructive" class="badge">Destructive</span>
<span variant="outline" class="badge">Outline</span>
<span
variant="custom"
class="badge"
style="--badge-background: var(--cyan-9)"
>
Custom
</span>
</div>
</body>
</html>
Composition workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Badge 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="badge-colors badge-icon badge-link badge-rtl badge-spinner badge-variants"
>
<main class="workflow-stack">
<div class="workflow-row" aria-label="Badge variants">
<span class="badge">Default</span>
<span variant="secondary" class="badge">Secondary</span>
<span variant="destructive" class="badge">Destructive</span>
<span variant="outline" class="badge">Outline</span>
<span variant="ghost" class="badge">Ghost</span>
</div>
<div class="workflow-row" aria-label="Badge custom colors">
<span class="badge-color-blue badge">Blue</span>
<span class="badge-color-green badge">Green</span>
<span class="badge-color-sky badge">Sky</span>
<span class="badge-color-purple badge">Purple</span>
<span class="badge-color-red badge">Red</span>
</div>
<div class="workflow-row" aria-label="Badges with icons">
<span variant="secondary" class="badge">
<svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="m9 12 2 2 4-4M12 3l2.2 1.5 2.7-.1.8 2.6 2.2 1.5-.9 2.5.9 2.5-2.2 1.5-.8 2.6-2.7-.1L12 21l-2.2-1.5-2.7.1-.8-2.6L4.1 15l.9-2.5-.9-2.5L6.3 7l.8-2.6 2.7.1L12 3Z"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Verified
</span>
<span variant="outline" class="badge">
Bookmark
<svg
icon="inline-end"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M6 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18l-6-4-6 4V4Z"
stroke="currentColor"
stroke-width="2"
stroke-linejoin="round"
/>
</svg>
</span>
<a href="#link" class="badge">
Open Link
<svg
icon="inline-end"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</a>
</div>
<div class="workflow-row" aria-label="Badges with loading status">
<span variant="destructive" class="badge">
<svg
icon="inline-start"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
Deleting
</span>
<span variant="secondary" class="badge">
Generating
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</span>
</div>
<div class="workflow-row" dir="rtl" aria-label="RTL badges">
<span class="badge">شارة</span>
<span variant="secondary" class="badge">ثانوي</span>
<span variant="destructive" class="badge">مدمر</span>
<span variant="outline" class="badge">مخطط</span>
</div>
</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. Styled inline authored content.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
icon | Authored | Direct icon position: inline-start or inline-end. |
variant | Authored | Presentation: default, secondary, destructive, outline, ghost, or custom. |
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
Styled inline authored content. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use the appropriate live-region or status semantics for dynamic feedback. Decorative feedback must stay hidden from assistive technology.
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.6 - breadcrumb
Page location navigation
Use a .breadcrumb navigation landmark with a native ordered list, links,
separators, and aria-current="page" for the current location. The class
distinguishes the trail from other navigation landmarks.
<nav aria-label="breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#">Home</a>
</li>
<li aria-hidden="true">/</li>
<li>
<span aria-current="page">Docs</span>
</li>
</ol>
</nav>
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 Breadcrumb</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="breadcrumb-basic breadcrumb-link"
>
<nav aria-label="breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#">Home</a>
</li>
<li aria-hidden="true">/</li>
<li>
<a href="#">Components</a>
</li>
<li aria-hidden="true">/</li>
<li>
<span aria-current="page">Breadcrumb</span>
</li>
</ol>
</nav>
</body>
</html>
Variants And Composition
Empty separator and ellipsis parts receive their standard icons. Author custom
separator content directly, and compose dropdowns with the existing semantic
Dropdown component.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Breadcrumb 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="breadcrumbSelection = 'None'; rtlBreadcrumbSelection = 'لا شيء'"
data-example="breadcrumb-demo breadcrumb-dropdown breadcrumb-ellipsis breadcrumb-rtl breadcrumb-separator"
>
<main>
<section aria-labelledby="breadcrumb-separator-heading">
<h2 id="breadcrumb-separator-heading">Custom separator</h2>
<nav aria-label="Custom separator breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#home">Home</a>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<a href="#components">Components</a>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<span aria-current="page" aria-disabled="true">Breadcrumb</span>
</li>
</ol>
</nav>
</section>
<section aria-labelledby="breadcrumb-ellipsis-heading">
<h2 id="breadcrumb-ellipsis-heading">Ellipsis</h2>
<nav aria-label="Ellipsis breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#home">Home</a>
</li>
<li aria-hidden="true"></li>
<li>
<span aria-hidden="true">...</span>
</li>
<li aria-hidden="true"></li>
<li>
<a href="#components">Components</a>
</li>
<li aria-hidden="true"></li>
<li>
<span aria-current="page" aria-disabled="true">Breadcrumb</span>
</li>
</ol>
</nav>
</section>
<section aria-labelledby="breadcrumb-demo-heading">
<h2 id="breadcrumb-demo-heading">Collapsed trail</h2>
<nav aria-label="Collapsed breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#home">Home</a>
</li>
<li aria-hidden="true"></li>
<li>
<span ng-dropdown-menu>
<button
type="button"
variant="ghost"
size="icon-sm"
aria-label="Toggle breadcrumb menu"
>
<span aria-hidden="true">...</span>
</button>
<menu>
<section>
<button ng-click="breadcrumbSelection = 'Documentation'">
Documentation
</button>
<button ng-click="breadcrumbSelection = 'Themes'">
Themes
</button>
<button ng-click="breadcrumbSelection = 'GitHub'">
GitHub
</button>
</section>
</menu>
</span>
</li>
<li aria-hidden="true"></li>
<li>
<a href="#components">Components</a>
</li>
<li aria-hidden="true"></li>
<li>
<span aria-current="page" aria-disabled="true">Breadcrumb</span>
</li>
</ol>
</nav>
<output> Selected: {{ breadcrumbSelection }} </output>
</section>
<section aria-labelledby="breadcrumb-dropdown-heading">
<h2 id="breadcrumb-dropdown-heading">Dropdown</h2>
<nav aria-label="Dropdown breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="#home">Home</a>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<span ng-dropdown-menu>
<button type="button">
Components
<svg
icon="inline-end"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<menu>
<section>
<button>Documentation</button>
<button>Themes</button>
<button>GitHub</button>
</section>
</menu>
</span>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<span aria-current="page" aria-disabled="true">Breadcrumb</span>
</li>
</ol>
</nav>
</section>
<section aria-labelledby="breadcrumb-rtl-heading" dir="rtl" lang="ar">
<h2 id="breadcrumb-rtl-heading">اتجاه من اليمين إلى اليسار</h2>
<nav aria-label="مسار التنقل" class="breadcrumb">
<ol>
<li>
<a href="#home">الرئيسية</a>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<span ng-dropdown-menu>
<button type="button">
المكونات
<svg
icon="inline-end"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<menu>
<section>
<button ng-click="rtlBreadcrumbSelection = 'التوثيق'">
التوثيق
</button>
<button ng-click="rtlBreadcrumbSelection = 'السمات'">
السمات
</button>
<button ng-click="rtlBreadcrumbSelection = 'جيت هاب'">
جيت هاب
</button>
</section>
</menu>
</span>
</li>
<li aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<circle cx="12" cy="12" r="2.5" />
</svg>
</li>
<li>
<span aria-current="page" aria-disabled="true">مسار التنقل</span>
</li>
</ol>
</nav>
<output> المحدد: {{ rtlBreadcrumbSelection }} </output>
</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 navigation and list composition.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-current | Authored | Current item or date state. |
dir | Authored | Text and interaction direction: ltr or rtl. |
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
Native navigation and list composition. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use semantic navigation landmarks and links. Expose the current destination with aria-current and keep keyboard order consistent with visual 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.
6.7 - button-group
Layout primitive for visually connected buttons and form controls.
Use fieldset[role="group"] around related commands or form controls. Set
orientation="vertical" for stacked groups. Use Toggle Group when the controls
represent one or more selectable values.
<fieldset role="group">
<button>One</button>
<hr />
<button>Two</button>
</fieldset>
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 Button Group</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="buttonGroupAction = 'None'"
data-example="button-group-demo button-group-orientation separator button-group-size button-group-split"
>
<main class="visual-example">
<section aria-label="Button group sizes">
<div aria-label="State ownership" role="group">
<button
id="button-group-unmanaged"
type="button"
variant="outline"
size="sm"
>
Small
</button>
<button
id="button-group-managed"
type="button"
variant="outline"
size="sm"
aria-pressed="true"
>
Button
</button>
<button type="button" variant="outline" size="sm">Group</button>
<button
type="button"
variant="outline"
size="icon-sm"
aria-label="Add small"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14M12 5v14" />
</svg>
</button>
</div>
<div role="group">
<button type="button" variant="outline">Default</button>
<button type="button" variant="outline">Button</button>
<button type="button" variant="outline">Group</button>
<button
type="button"
variant="outline"
size="icon"
aria-label="Add default"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14M12 5v14" />
</svg>
</button>
</div>
<div role="group">
<button type="button" variant="outline" size="lg">Large</button>
<button type="button" variant="outline" size="lg">Button</button>
<button type="button" variant="outline" size="lg">Group</button>
<button
type="button"
variant="outline"
size="icon-lg"
aria-label="Add large"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14M12 5v14" />
</svg>
</button>
</div>
</section>
<fieldset orientation="vertical" aria-label="Media controls" role="group">
<button
type="button"
variant="outline"
size="icon"
aria-label="Increase"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14M12 5v14" />
</svg>
</button>
<hr />
<button
type="button"
variant="outline"
size="icon"
aria-label="Decrease"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14" />
</svg>
</button>
</fieldset>
<section aria-label="Button group compositions">
<div role="group">
<button
type="button"
variant="secondary"
size="sm"
ng-click="buttonGroupAction = 'Copy'"
>
Copy
</button>
<hr aria-orientation="vertical" />
<button
type="button"
variant="secondary"
size="sm"
ng-click="buttonGroupAction = 'Paste'"
>
Paste
</button>
</div>
<div role="group">
<button
type="button"
variant="secondary"
ng-click="buttonGroupAction = 'Button'"
>
Button
</button>
<hr aria-orientation="vertical" />
<button
type="button"
variant="secondary"
size="icon"
aria-label="Add item"
ng-click="buttonGroupAction = 'Add'"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M5 12h14M12 5v14" />
</svg>
</button>
</div>
</section>
<output class="output">Action: {{ buttonGroupAction }}</output>
</main>
</body>
</html>
Composition Workflows
Button groups can connect nested groups, inputs, input groups, Select, Dropdown,
and Popover triggers. Each composed component retains its own behavior and
application state.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Button Group 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="toolbarAction = 'None'; searchTerm = ''; voiceEnabled = false; currency = '$'; rtlAction = 'لا شيء'"
data-example="button-group-demo button-group-dropdown button-group-input button-group-input-group button-group-nested button-group-popover button-group-rtl button-group-select"
>
<main class="button-group-workflows">
<section
class="button-group-workflow-section button-group-menu-stage"
aria-labelledby="button-group-toolbar-heading"
>
<h2 id="button-group-toolbar-heading">Toolbar</h2>
<fieldset aria-label="Message actions" role="group">
<div role="group">
<button
type="button"
variant="outline"
size="icon"
aria-label="Go Back"
>
←
</button>
</div>
<div role="group">
<button
type="button"
variant="outline"
ng-click="toolbarAction = 'Archive'"
>
Archive
</button>
<button
type="button"
variant="outline"
ng-click="toolbarAction = 'Report'"
>
Report
</button>
</div>
<div role="group">
<button
type="button"
variant="outline"
ng-click="toolbarAction = 'Snooze'"
>
Snooze
</button>
<span ng-dropdown-menu>
<button
type="button"
variant="outline"
size="icon"
aria-label="More Options"
>
•••
</button>
<menu align="end" style="--menu-width: 10rem">
<section>
<button ng-click="toolbarAction = 'Mark as Read'">
Mark as Read
</button>
<button ng-click="toolbarAction = 'Archive'">Archive</button>
<button ng-click="toolbarAction = 'Snooze'">Snooze</button>
</section>
<span></span>
<button
variant="destructive"
ng-click="toolbarAction = 'Trash'"
>
Trash
</button>
</menu>
</span>
</div>
</fieldset>
<output class="button-group-output">
Action: {{ toolbarAction }}
</output>
</section>
<section
class="button-group-workflow-section button-group-menu-stage"
aria-labelledby="button-group-dropdown-heading"
>
<h2 id="button-group-dropdown-heading">Split dropdown</h2>
<fieldset aria-label="Follow actions" role="group">
<button type="button" variant="outline">Follow</button>
<span ng-dropdown-menu>
<button
type="button"
variant="outline"
aria-label="More follow actions"
></button>
<menu align="end" style="--menu-width: 11rem">
<section>
<button>Mute Conversation</button>
<button>Mark as Read</button>
<button>Report Conversation</button>
<button>Block User</button>
<button>Share Conversation</button>
<button>Copy Conversation</button>
</section>
<span></span>
<button variant="destructive">Delete Conversation</button>
</menu>
</span>
</fieldset>
</section>
<section
class="button-group-workflow-section"
aria-labelledby="button-group-input-heading"
>
<h2 id="button-group-input-heading">Search input</h2>
<div role="group">
<input
ng-model="searchTerm"
placeholder="Search..."
aria-label="Search query"
/>
<button
type="button"
variant="outline"
aria-label="Search"
ng-click="toolbarAction = searchTerm || 'Search'"
>
⌕
</button>
</div>
<output class="button-group-output">
Query: {{ searchTerm || 'Empty' }}
</output>
</section>
<section
class="button-group-workflow-section"
aria-labelledby="button-group-nested-heading"
>
<h2 id="button-group-nested-heading">Nested input group</h2>
<div role="group" style="--radius-md: var(--radius-full)">
<div role="group">
<button
type="button"
variant="outline"
size="icon"
aria-label="Add attachment"
>
+
</button>
</div>
<div role="group">
<div class="input-group">
<input placeholder="Send a message..." aria-label="Message" />
<span align="inline-end">⌁</span>
</div>
</div>
</div>
</section>
<section
class="button-group-workflow-section"
aria-labelledby="button-group-voice-heading"
>
<h2 id="button-group-voice-heading">Voice mode</h2>
<div role="group" style="--radius-md: var(--radius-full)">
<div role="group">
<button
type="button"
variant="outline"
size="icon"
aria-label="Add message item"
>
+
</button>
</div>
<div role="group">
<div class="input-group">
<input
placeholder="{{ voiceEnabled ? 'Record and send audio...' : 'Send a message...' }}"
ng-disabled="voiceEnabled"
aria-label="Voice message"
/>
<span align="inline-end">
<button
type="button"
size="icon-xs"
aria-label="Voice Mode"
aria-pressed="{{ voiceEnabled }}"
ng-click="voiceEnabled = !voiceEnabled"
>
⌁
</button>
</span>
</div>
</div>
</div>
</section>
<section
class="button-group-workflow-section button-group-popover-stage"
aria-labelledby="button-group-popover-heading"
>
<h2 id="button-group-popover-heading">Popover</h2>
<div role="group">
<button type="button" variant="outline">◇ Copilot</button>
<span>
<button
type="button"
variant="outline"
size="icon"
aria-label="Open Popover"
popovertarget="popover-button-group-workflows-1-content"
>
⌄
</button>
<aside
side="bottom"
aria-label="Copilot task"
class="button-group-popover-content"
id="popover-button-group-workflows-1-content"
align="center"
popover
>
<header>
<h3>Start a new task with Copilot</h3>
<p>Describe your task in natural language.</p>
</header>
<label class="visually-hidden" for="copilot-task"
>Task Description</label
>
<textarea id="copilot-task" placeholder="I need to..."></textarea>
<p class="muted">Copilot will open a pull request for review.</p>
</aside>
</span>
</div>
</section>
<section
class="button-group-workflow-section button-group-select-stage"
aria-labelledby="button-group-select-heading"
>
<h2 id="button-group-select-heading">Currency select</h2>
<div role="group">
<div role="group">
<select aria-label="Currency" ng-model="currency">
<option value="$">$ US Dollar</option>
<option value="€">€ Euro</option>
<option value="£">£ British Pound</option>
</select>
<input
placeholder="10.00"
inputmode="numeric"
aria-label="Amount"
/>
</div>
<div role="group">
<button
type="button"
variant="outline"
size="icon"
aria-label="Send"
>
→
</button>
</div>
</div>
</section>
<section
class="button-group-workflow-section button-group-menu-stage button-group-workflow-wide"
aria-labelledby="button-group-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="button-group-rtl-heading">اتجاه من اليمين إلى اليسار</h2>
<fieldset aria-label="إجراءات الرسالة" role="group">
<div role="group">
<button type="button" variant="outline">أرشفة</button>
<button type="button" variant="outline">تقرير</button>
</div>
<div role="group">
<button type="button" variant="outline">تأجيل</button>
<span ng-dropdown-menu>
<button
type="button"
variant="outline"
size="icon"
aria-label="المزيد من الخيارات"
>
•••
</button>
<menu align="end" style="--menu-width: 10rem">
<button ng-click="rtlAction = 'وضع علامة كمقروء'">
وضع علامة كمقروء
</button>
<button ng-click="rtlAction = 'أرشفة'">أرشفة</button>
<span></span>
<button
variant="destructive"
ng-click="rtlAction = 'سلة المهملات'"
>
سلة المهملات
</button>
</menu>
</span>
</div>
</fieldset>
<output class="button-group-output"> الإجراء: {{ rtlAction }} </output>
</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. Grouped native actions.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-orientation | Authored | Use vertical on a direct separator when it divides controls along the inline axis. |
orientation | Authored | Group layout: vertical; omit for the horizontal layout. |
role | Authored | Explicit semantic role when native HTML does not provide one. |
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
Grouped native actions. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native button whenever the control performs an action. Keep an accessible name, preserve visible focus, and use disabled for unavailable native controls.
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.8 - card
Sectioned content container using semantic parts.
Use article.card with optional semantic header, content, footer, and action
regions. Direct headers, headings, and header paragraphs need no part classes.
<article class="card">
<header>
<h2>Title</h2>
<p>Optional description</p>
<menu>Action</menu>
</header>
<section>Content</section>
<footer>Footer</footer>
</article>
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 Card</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="card-demo">
<article class="visual-example card">
<header>
<h2>Login to your account</h2>
<p>Enter your email below to login to your account</p>
<menu>
<button variant="link" type="button">Sign Up</button>
</menu>
</header>
<section>
<form class="card-form" id="login-form">
<div class="card-field">
<label for="card-email">Email</label>
<input
id="card-email"
type="email"
placeholder="m@example.com"
required
/>
</div>
<div class="card-field">
<div class="card-label-row">
<label for="card-password">Password</label>
<a href="#forgot-password">Forgot your password?</a>
</div>
<input id="card-password" type="password" required />
</div>
</form>
</section>
<footer class="card-footer-stacked">
<button type="submit" form="login-form">Login</button>
<button variant="outline" type="button">Login with Google</button>
</footer>
</article>
</body>
</html>
Image And RTL
Card content remains ordinary semantic HTML. Use local images, logical CSS
properties, and AngularTS form or command directives for application state.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Card 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="cardAction='No event selected'; rtl={email:'',password:'',status:'جاهز'}; smallCardAction='No report action'"
data-example="card-image card-rtl card-small"
>
<main class="card-workflows" aria-label="Card reference workflows">
<section class="card-workflow" aria-labelledby="card-image-heading">
<h2 id="card-image-heading">Image card</h2>
<article class="card-image-card card">
<div class="card-image-overlay" aria-hidden="true"></div>
<img
class="card-cover-image"
src="../../images/avatars/01.png"
alt="Abstract event cover"
/>
<header>
<menu>
<span variant="secondary" class="badge">Featured</span>
</menu>
<h2>Design systems meetup</h2>
<p>
A practical talk on component APIs, accessibility, and shipping
faster.
</p>
</header>
<footer>
<button
type="button"
class="card-full-button"
ng-click="cardAction='Viewing Design systems meetup'"
>
View Event
</button>
</footer>
</article>
<output class="card-workflow-output">{{ cardAction }}</output>
</section>
<section
class="card-workflow"
aria-labelledby="card-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="card-rtl-heading">بطاقة من اليمين إلى اليسار</h2>
<article class="card-rtl-card card" dir="rtl">
<header>
<h2>تسجيل الدخول إلى حسابك</h2>
<p>أدخل بريدك الإلكتروني أدناه لتسجيل الدخول إلى حسابك</p>
<menu>
<button
variant="link"
type="button"
ng-click="rtl.status='إنشاء حساب جديد'"
>
إنشاء حساب
</button>
</menu>
</header>
<section>
<form
class="card-form"
id="rtl-login-form"
ng-submit="rtl.status='تم تسجيل الدخول باسم ' + rtl.email"
>
<div class="card-field">
<label for="card-email-rtl">البريد الإلكتروني</label>
<input
id="card-email-rtl"
type="email"
placeholder="m@example.com"
ng-model="rtl.email"
required
/>
</div>
<div class="card-field">
<div class="card-label-row">
<label for="card-password-rtl">كلمة المرور</label>
<a href="#forgot-password-rtl">نسيت كلمة المرور؟</a>
</div>
<input
id="card-password-rtl"
type="password"
ng-model="rtl.password"
required
/>
</div>
</form>
</section>
<footer class="card-footer-stacked">
<button type="submit" form="rtl-login-form">تسجيل الدخول</button>
<button
variant="outline"
type="button"
ng-click="rtl.status='متابعة باستخدام Google'"
>
تسجيل الدخول باستخدام Google
</button>
</footer>
</article>
<output class="card-workflow-output"> الحالة: {{ rtl.status }} </output>
</section>
<section class="card-workflow" aria-labelledby="card-small-heading">
<h2 id="card-small-heading">Small card</h2>
<article size="sm" class="card-small-card card">
<header>
<h2>Scheduled reports</h2>
<p>Weekly snapshots. No more manual exports.</p>
</header>
<section>
<ul class="card-feature-list">
<li>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><span>Choose a schedule (daily, or weekly).</span>
</li>
<li>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><span>Send to channels or specific teammates.</span>
</li>
<li>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><span>Include charts, tables, and key metrics.</span>
</li>
</ul>
</section>
<footer class="card-footer-stacked">
<button
size="sm"
type="button"
ng-click="smallCardAction='Scheduled reports setup'"
>
Set up scheduled reports
</button>
<button
variant="outline"
size="sm"
type="button"
ng-click="smallCardAction='Showing report updates'"
>
See what's new
</button>
</footer>
</article>
<output class="card-workflow-output">{{ smallCardAction }}</output>
</section>
</main>
</body>
</html>
Section States
Card sections are optional. CSS adapts spacing to the authored sections and
size="sm" attribute; no directive runs for a card.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Card State 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>
<main class="component-state-grid" aria-label="Card state contracts">
<section
class="component-state-section"
aria-labelledby="complete-card-title"
>
<h2 id="complete-card-title">Complete card</h2>
<article aria-label="Complete card" class="card">
<header>
<h2>Quarterly planning</h2>
<p>Review the agenda before Monday.</p>
<menu>
<button variant="ghost" size="sm" type="button">Edit</button>
</menu>
</header>
<section>Four topics are ready for review.</section>
<footer>Updated today</footer>
</article>
</section>
<section
class="component-state-section"
aria-labelledby="minimal-card-title"
>
<h2 id="minimal-card-title">Minimal card</h2>
<article aria-label="Minimal card" class="card-minimal-state card">
No optional sections are required.
</article>
</section>
<section
class="component-state-section"
aria-labelledby="compact-card-title"
>
<h2 id="compact-card-title">Compact card</h2>
<article size="sm" aria-label="Compact card" class="card">
<header>
<h2>Storage</h2>
</header>
<footer>8.4 GB available</footer>
</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. Semantic content composition.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
size | Authored | Use sm for compact spacing; omit for the default size. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|
--card-padding-block | Block padding; defaults to four spacing units, or three for size=sm. |
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
Semantic content composition. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
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.
6.9 - chart
HTML-first chart container, legend, axis, and tooltip primitives
Use Chart to frame application-rendered HTML, SVG, canvas, or a locally bundled
chart library with a consistent container, axis, legend, and tooltip contract.
For simple authored HTML plots, data-value and data-color synchronize to
--value and --chart-color.
<figure aria-label="Monthly visitors" class="chart">
<section>
<hr />
<ul>
<li>
<span
aria-label="January desktop"
data-value="72%"
data-color="var(--chart-1)"
></span>
</li>
</ul>
</section>
<footer><span>Jan</span></footer>
</figure>
AngularCSS does not implement a chart engine. Plotting, scales, data,
formatting, hover selection, and active-series state remain with authored HTML,
the application’s selected chart library, and AngularTS. This keeps Chart from
covering AngularTS application behavior while providing stable semantic and
customization hooks.
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 Chart</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="chart-example">
<figure
class="visual-example chart"
aria-label="Desktop and mobile visitors from January through June"
>
<section>
<ul>
<li>
<span
role="img"
aria-label="January desktop"
data-value="61%"
data-color="#2563eb"
style="--value: 61%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="January mobile"
data-value="26%"
data-color="#60a5fa"
style="--value: 26%; --chart-color: #60a5fa"
></span>
</li>
<li>
<span
role="img"
aria-label="February desktop"
data-value="100%"
data-color="#2563eb"
style="--value: 100%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="February mobile"
data-value="66%"
data-color="#60a5fa"
style="--value: 66%; --chart-color: #60a5fa"
></span>
</li>
<li>
<span
role="img"
aria-label="March desktop"
data-value="78%"
data-color="#2563eb"
style="--value: 78%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="March mobile"
data-value="39%"
data-color="#60a5fa"
style="--value: 39%; --chart-color: #60a5fa"
></span>
</li>
<li>
<span
role="img"
aria-label="April desktop"
data-value="24%"
data-color="#2563eb"
style="--value: 24%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="April mobile"
data-value="62%"
data-color="#60a5fa"
style="--value: 62%; --chart-color: #60a5fa"
></span>
</li>
<li>
<span
role="img"
aria-label="May desktop"
data-value="69%"
data-color="#2563eb"
style="--value: 69%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="May mobile"
data-value="43%"
data-color="#60a5fa"
style="--value: 43%; --chart-color: #60a5fa"
></span>
</li>
<li>
<span
role="img"
aria-label="June desktop"
data-value="70%"
data-color="#2563eb"
style="--value: 70%; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="June mobile"
data-value="46%"
data-color="#60a5fa"
style="--value: 46%; --chart-color: #60a5fa"
></span>
</li>
</ul>
</section>
</figure>
</body>
</html>
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Chart 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="chartData=[{month:'January',short:'Jan',desktop:186,mobile:80,d:'61%',m:'26%'},{month:'February',short:'Feb',desktop:305,mobile:200,d:'100%',m:'66%'},{month:'March',short:'Mar',desktop:237,mobile:120,d:'78%',m:'39%'},{month:'April',short:'Apr',desktop:73,mobile:190,d:'24%',m:'62%'},{month:'May',short:'May',desktop:209,mobile:130,d:'69%',m:'43%'},{month:'June',short:'Jun',desktop:214,mobile:140,d:'70%',m:'46%'}]; tooltip={visible:false}; legendTip={visible:false}"
data-example="chart-example-grid chart-example-axis chart-example-tooltip chart-example-legend"
>
<main class="chart-workflow-grid" aria-label="Chart composition workflows">
<section class="chart-workflow" aria-labelledby="chart-grid-heading">
<h2 id="chart-grid-heading">Grid</h2>
<figure
class="chart-reference-demo chart"
aria-label="Visitor chart with horizontal grid"
>
<section>
<hr />
<ul>
<li ng-repeat="point in chartData">
<span
role="img"
aria-label="{{ point.month }} desktop"
data-value="{{ point.d }}"
data-color="#2563eb"
style="--value: {{ point.d }}; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="{{ point.month }} mobile"
data-value="{{ point.m }}"
data-color="#60a5fa"
style="--value: {{ point.m }}; --chart-color: #60a5fa"
></span>
</li>
</ul>
</section>
</figure>
</section>
<section class="chart-workflow" aria-labelledby="chart-axis-heading">
<h2 id="chart-axis-heading">Axis</h2>
<figure
class="chart-reference-demo chart"
aria-label="Visitor chart with horizontal axis"
>
<section>
<hr />
<ul>
<li ng-repeat="point in chartData">
<span
role="img"
aria-label="{{ point.month }} desktop"
data-value="{{ point.d }}"
data-color="#2563eb"
style="--value: {{ point.d }}; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="{{ point.month }} mobile"
data-value="{{ point.m }}"
data-color="#60a5fa"
style="--value: {{ point.m }}; --chart-color: #60a5fa"
></span>
</li>
</ul>
</section>
<footer>
<span ng-repeat="point in chartData"> {{ point.short }} </span>
</footer>
</figure>
</section>
<section class="chart-workflow" aria-labelledby="chart-tooltip-heading">
<h2 id="chart-tooltip-heading">Tooltip</h2>
<figure
class="chart-reference-demo chart"
aria-label="Visitor chart with tooltip"
>
<section>
<hr />
<ul>
<li
ng-repeat="point in chartData"
ng-mouseenter="tooltip.visible=true;tooltip.month=point.month;tooltip.desktop=point.desktop;tooltip.mobile=point.mobile"
ng-mouseleave="tooltip.visible=false"
>
<span
role="img"
aria-label="{{ point.month }} desktop"
data-value="{{ point.d }}"
data-color="#2563eb"
style="--value: {{ point.d }}; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="{{ point.month }} mobile"
data-value="{{ point.m }}"
data-color="#60a5fa"
style="--value: {{ point.m }}; --chart-color: #60a5fa"
></span>
</li>
</ul>
<output class="chart-floating-tooltip" ng-if="tooltip.visible">
<strong>{{ tooltip.month }}</strong>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="#2563eb"
style="--chart-color: #2563eb"
></span
>Desktop
</dt>
<dd>{{ tooltip.desktop }}</dd>
</div>
<div>
<dt>
<span
aria-hidden="true"
data-color="#60a5fa"
style="--chart-color: #60a5fa"
></span
>Mobile
</dt>
<dd>{{ tooltip.mobile }}</dd>
</div>
</dl>
</output>
</section>
<footer>
<span ng-repeat="point in chartData"> {{ point.short }} </span>
</footer>
</figure>
</section>
<section class="chart-workflow" aria-labelledby="chart-legend-heading">
<h2 id="chart-legend-heading">Legend</h2>
<figure
class="chart-reference-demo chart"
aria-label="Visitor chart with legend and tooltip"
>
<section>
<hr />
<ul>
<li
ng-repeat="point in chartData"
ng-mouseenter="legendTip.visible=true;legendTip.month=point.month;legendTip.desktop=point.desktop;legendTip.mobile=point.mobile"
ng-mouseleave="legendTip.visible=false"
>
<span
role="img"
aria-label="{{ point.month }} desktop"
data-value="{{ point.d }}"
data-color="#2563eb"
style="--value: {{ point.d }}; --chart-color: #2563eb"
></span>
<span
role="img"
aria-label="{{ point.month }} mobile"
data-value="{{ point.m }}"
data-color="#60a5fa"
style="--value: {{ point.m }}; --chart-color: #60a5fa"
></span>
</li>
</ul>
<output class="chart-floating-tooltip" ng-if="legendTip.visible">
<strong>{{ legendTip.month }}</strong>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="#2563eb"
style="--chart-color: #2563eb"
></span
>Desktop
</dt>
<dd>{{ legendTip.desktop }}</dd>
</div>
<div>
<dt>
<span
aria-hidden="true"
data-color="#60a5fa"
style="--chart-color: #60a5fa"
></span
>Mobile
</dt>
<dd>{{ legendTip.mobile }}</dd>
</div>
</dl>
</output>
</section>
<footer>
<span ng-repeat="point in chartData"> {{ point.short }} </span>
</footer>
<ul>
<li>
<span data-color="#2563eb" style="--chart-color: #2563eb"></span
>Desktop
</li>
<li>
<span data-color="#60a5fa" style="--chart-color: #60a5fa"></span
>Mobile
</li>
</ul>
</figure>
</section>
</main>
</body>
</html>
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Chart Compositions</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="activeChart='desktop'; demoTip={visible:false}; rtlTip={visible:false}; interactiveData=[{date:'Apr 1',d:222,m:150,dp:'49%',mp:'36%'},{date:'Apr 2',d:97,m:180,dp:'21%',mp:'43%'},{date:'Apr 3',d:167,m:120,dp:'37%',mp:'29%'},{date:'Apr 4',d:242,m:260,dp:'53%',mp:'62%'},{date:'Apr 5',d:373,m:290,dp:'82%',mp:'69%'},{date:'Apr 6',d:301,m:340,dp:'66%',mp:'81%'},{date:'Apr 7',d:245,m:180,dp:'54%',mp:'43%'},{date:'Apr 8',d:409,m:320,dp:'90%',mp:'76%'},{date:'Apr 9',d:59,m:110,dp:'13%',mp:'26%'},{date:'Apr 10',d:261,m:190,dp:'57%',mp:'45%'},{date:'Apr 11',d:327,m:350,dp:'72%',mp:'83%'},{date:'Apr 12',d:292,m:210,dp:'64%',mp:'50%'},{date:'Apr 13',d:342,m:380,dp:'75%',mp:'90%'},{date:'Apr 14',d:137,m:220,dp:'30%',mp:'52%'},{date:'Apr 15',d:120,m:170,dp:'26%',mp:'40%'},{date:'Apr 16',d:138,m:190,dp:'30%',mp:'45%'},{date:'Apr 17',d:446,m:360,dp:'98%',mp:'86%'},{date:'Apr 18',d:364,m:410,dp:'80%',mp:'98%'},{date:'Apr 19',d:243,m:180,dp:'54%',mp:'43%'},{date:'Apr 20',d:89,m:150,dp:'20%',mp:'36%'},{date:'Apr 21',d:137,m:200,dp:'30%',mp:'48%'},{date:'Apr 22',d:224,m:170,dp:'49%',mp:'40%'},{date:'Apr 23',d:138,m:230,dp:'30%',mp:'55%'},{date:'Apr 24',d:387,m:290,dp:'85%',mp:'69%'},{date:'Apr 25',d:215,m:250,dp:'47%',mp:'60%'},{date:'Apr 26',d:75,m:130,dp:'17%',mp:'31%'},{date:'Apr 27',d:383,m:420,dp:'84%',mp:'100%'},{date:'Apr 28',d:122,m:180,dp:'27%',mp:'43%'},{date:'Apr 29',d:315,m:240,dp:'69%',mp:'57%'},{date:'Apr 30',d:454,m:380,dp:'100%',mp:'90%'}]; rtlData=[{month:'يناير',short:'ينا',desktop:186,mobile:80,d:'61%',m:'26%'},{month:'فبراير',short:'فبر',desktop:305,mobile:200,d:'100%',m:'66%'},{month:'مارس',short:'مار',desktop:237,mobile:120,d:'78%',m:'39%'},{month:'أبريل',short:'أبر',desktop:73,mobile:190,d:'24%',m:'62%'},{month:'مايو',short:'ماي',desktop:209,mobile:130,d:'69%',m:'43%'},{month:'يونيو',short:'يون',desktop:214,mobile:140,d:'70%',m:'46%'}]"
data-example="chart-demo chart-rtl chart-tooltip"
>
<main
class="chart-composition-grid"
aria-label="Chart reference compositions"
>
<article class="chart-interactive-card chart-composition-wide card">
<header class="chart-interactive-header">
<div class="chart-interactive-copy">
<h2>Bar Chart - Interactive</h2>
<p>Showing total visitors for the last 3 months</p>
</div>
<div class="chart-series-controls" aria-label="Visitor series">
<button
type="button"
variant="ghost"
aria-pressed="{{ activeChart == 'desktop' }}"
ng-click="activeChart='desktop'"
>
<span>Desktop</span><strong>7,324</strong>
</button>
<button
type="button"
variant="ghost"
aria-pressed="{{ activeChart == 'mobile' }}"
ng-click="activeChart='mobile'"
>
<span>Mobile</span><strong>7,250</strong>
</button>
</div>
</header>
<section class="chart-interactive-content">
<figure
class="chart-interactive-demo chart"
aria-label="Interactive daily visitors"
>
<section>
<hr />
<div class="chart-daily-bars">
<span
role="img"
ng-repeat="point in interactiveData"
aria-label="{{ point.date }} {{ activeChart }}"
data-value="{{ activeChart == 'desktop' ? point.dp : point.mp }}"
data-color="{{ activeChart == 'desktop' ? 'var(--chart-2)' : 'var(--chart-1)' }}"
ng-mouseenter="demoTip.visible=true;demoTip.date=point.date;demoTip.value=activeChart == 'desktop' ? point.d : point.m"
ng-mouseleave="demoTip.visible=false"
style="--value: {{ activeChart == 'desktop' ? point.dp : point.mp }}; --chart-color: {{ activeChart == 'desktop' ? 'var(--chart-2)' : 'var(--chart-1)' }}"
></span>
</div>
<output class="chart-floating-tooltip" ng-if="demoTip.visible">
<strong>{{ demoTip.date }}, 2024</strong>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="{{ activeChart == 'desktop' ? 'var(--chart-2)' : 'var(--chart-1)' }}"
style="--chart-color: {{ activeChart == 'desktop' ? 'var(--chart-2)' : 'var(--chart-1)' }}"
></span>
{{ activeChart == 'desktop' ? 'Desktop' : 'Mobile' }}
</dt>
<dd>{{ demoTip.value }}</dd>
</div>
</dl>
</output>
</section>
<footer class="chart-date-axis">
<span>Apr 1</span>
<span>Apr 8</span>
<span>Apr 15</span>
<span>Apr 22</span>
<span>Apr 30</span>
</footer>
</figure>
</section>
</article>
<section
class="chart-composition"
aria-labelledby="chart-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="chart-rtl-heading">مخطط من اليمين إلى اليسار</h2>
<figure
class="chart-reference-demo chart"
aria-label="زوار سطح المكتب والجوال"
>
<section>
<hr />
<ul>
<li
ng-repeat="point in rtlData"
ng-mouseenter="rtlTip.visible=true;rtlTip.month=point.month;rtlTip.desktop=point.desktop;rtlTip.mobile=point.mobile"
ng-mouseleave="rtlTip.visible=false"
>
<span
role="img"
aria-label="{{ point.month }} سطح المكتب"
data-value="{{ point.d }}"
data-color="var(--chart-2)"
style="--value: {{ point.d }}; --chart-color: var(--chart-2)"
></span>
<span
role="img"
aria-label="{{ point.month }} الجوال"
data-value="{{ point.m }}"
data-color="var(--chart-1)"
style="--value: {{ point.m }}; --chart-color: var(--chart-1)"
></span>
</li>
</ul>
<output class="chart-floating-tooltip" ng-if="rtlTip.visible">
<strong>{{ rtlTip.month }}</strong>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="var(--chart-2)"
style="--chart-color: var(--chart-2)"
></span
>سطح المكتب
</dt>
<dd>{{ rtlTip.desktop }}</dd>
</div>
<div>
<dt>
<span
aria-hidden="true"
data-color="var(--chart-1)"
style="--chart-color: var(--chart-1)"
></span
>الجوال
</dt>
<dd>{{ rtlTip.mobile }}</dd>
</div>
</dl>
</output>
</section>
<footer>
<span ng-repeat="point in rtlData"> {{ point.short }} </span>
</footer>
<ul>
<li>
<span
data-color="var(--chart-2)"
style="--chart-color: var(--chart-2)"
></span
>سطح المكتب
</li>
<li>
<span
data-color="var(--chart-1)"
style="--chart-color: var(--chart-1)"
></span
>الجوال
</li>
</ul>
</figure>
</section>
<section
class="chart-composition"
aria-labelledby="chart-tooltip-gallery-heading"
>
<h2 id="chart-tooltip-gallery-heading">Tooltip anatomy</h2>
<figure
class="chart-tooltip-gallery chart"
aria-label="Chart tooltip anatomy examples"
>
<output>
<strong>Page Views</strong>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="var(--chart-1)"
style="--chart-color: var(--chart-1)"
></span
>Desktop
</dt>
<dd>186</dd>
</div>
<div>
<dt>
<span
aria-hidden="true"
data-color="var(--chart-2)"
style="--chart-color: var(--chart-2)"
></span
>Mobile
</dt>
<dd>80</dd>
</div>
</dl>
</output>
<output>
<dl>
<div>
<dt>
<span
aria-hidden="true"
indicator="dashed"
data-color="var(--chart-3)"
style="--chart-color: var(--chart-3)"
></span
>Chrome
</dt>
<dd>1,286</dd>
</div>
<div>
<dt>
<span
aria-hidden="true"
indicator="dashed"
data-color="var(--chart-4)"
style="--chart-color: var(--chart-4)"
></span
>Firefox
</dt>
<dd>1,000</dd>
</div>
</dl>
</output>
<output>
<dl>
<div>
<dt>
<span
aria-hidden="true"
indicator="line"
data-color="var(--chart-3)"
style="--chart-color: var(--chart-3)"
></span
><strong>Page Views</strong><br />Desktop
</dt>
<dd>12,486</dd>
</div>
</dl>
</output>
<output>
<dl>
<div>
<dt>
<span
aria-hidden="true"
data-color="var(--chart-1)"
style="--chart-color: var(--chart-1)"
></span
>Chrome
</dt>
<dd>1,286</dd>
</div>
</dl>
</output>
</figure>
</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. Authored figures, tables, and CSS variables.
Anatomy
Root styling selector
Semantic structure
Apply .chart to an accessible figure. Compose its optional title, plot, grid, grouped bars, axis, legend, and tooltip from semantic header, section, hr, ul, li, footer, output, and description-list elements; no anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
data-color | Authored | Series color key used by the example or application to set --chart-color. |
data-value | Authored | Authored bar height as a percentage when --value is not set. |
indicator | Authored | Legend indicator: line or dashed; omit for a solid mark. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|
--chart-color | Color for an authored series, mark, or legend indicator. |
--value | Bar height as a percentage; falls back to data-value and then 50%. |
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
Semantic figure, heading, list, and data markup owns chart meaning. CSS variables provide visual values and colors; authored HTML, SVG, canvas, or an application-selected chart library owns plotting, scales, data, formatting, and interaction. AngularCSS registers no chart directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give every chart root a useful accessible name and provide a textual or tabular equivalent when exact values matter. Bars expose authored labels and values; axes and legends are lists; grid decoration is hidden; visible tooltips are status regions. Never use color as the only distinction between series.
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.10 - description-list
Semantic record details
Use a native description list for stable record labels and values. AngularCSS
adds responsive row presentation without changing the relationship between terms
and descriptions.
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 Description List</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="description-list-demo">
<dl class="visual-example" aria-label="Account details">
<div>
<dt>Account owner</dt>
<dd>Ada Lovelace</dd>
</div>
<div>
<dt>Email</dt>
<dd>ada@example.com</dd>
</div>
<div>
<dt>Plan</dt>
<dd>Enterprise</dd>
</div>
<div>
<dt>Last updated</dt>
<dd><time datetime="2026-09-05">5 September 2026</time></dd>
</div>
</dl>
</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 description-list structure for record details.
Anatomy
Root styling selector
dl:has(> div > dt):has(> div > dd)
Semantic structure
Use a native dl and wrap each related dt and dd group in a direct div so rows adapt without any component or part classes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
orientation | Authored | Row layout: horizontal or vertical; omit to become vertical 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
Description List styles native terms and descriptions for record details. The application owns values, formatting, redaction, and conditional rendering.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use native dl, dt, and dd elements. Group each term and its descriptions in a div when row styling is needed, and keep sensitive values subject to application authorization.
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.11 - disclosure
HTML-first disclosure state and trigger/panel relationships
Native details and summary own click, keyboard, focus, and disclosure state.
AngularCSS only styles the authored structure. AngularTS may observe native
events when the application needs the state.
<details class="disclosure">
<summary>Order details</summary>
<div>Shipping address and item details.</div>
</details>
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 Disclosure</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="disclosure-demo">
<details class="disclosure visual-example">
<summary>
<header>
<h2>Order #4189</h2>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="m7 15 5 5 5-5M7 9l5-5 5 5" />
</svg>
<span class="visually-hidden">Toggle details</span>
</header>
<p><span>Status</span><strong>Shipped</strong></p>
</summary>
<section>
<article>
<p><strong>Shipping address</strong></p>
<p>100 Market St, San Francisco</p>
</article>
<article>
<p><strong>Items</strong></p>
<p>2x Studio Headphones</p>
</article>
</section>
</details>
</body>
</html>
Basic, settings, and RTL
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Disclosure 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="disclosure-basic disclosure-rtl disclosure-settings"
>
<main class="disclosure-workflow-grid" aria-label="Disclosure workflows">
<section
class="disclosure-workflow"
aria-labelledby="disclosure-basic-heading"
>
<h2 id="disclosure-basic-heading">Basic</h2>
<div class="disclosure-basic-card card">
<section>
<details class="disclosure disclosure-product">
<summary>
<span>Product details</span>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="m6 9 6 6 6-6" />
</svg>
</summary>
<div>
<p>
This panel can be expanded or collapsed to reveal additional
content.
</p>
<button size="xs">Learn More</button>
</div>
</details>
</section>
</div>
</section>
<section
class="disclosure-workflow"
aria-labelledby="disclosure-settings-heading"
>
<h2 id="disclosure-settings-heading">Settings</h2>
<div size="sm" class="disclosure-settings-card card">
<header>
<h2>Radius</h2>
<p>Set the corner radius of the element.</p>
</header>
<section>
<section class="disclosure-settings">
<div class="disclosure-settings-fields">
<label class="visually-hidden" for="radius-x">Radius X</label>
<input id="radius-x" type="number" value="0" />
<label class="visually-hidden" for="radius-y">Radius Y</label>
<input id="radius-y" type="number" value="0" />
<details class="disclosure disclosure-settings-disclosure">
<summary aria-label="Toggle additional radius settings">
<svg
class="disclosure-maximize"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3M3 16v3a2 2 0 0 0 2 2h3m8 0h3a2 2 0 0 0 2-2v-3"
/>
</svg>
<svg
class="disclosure-minimize"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3M3 16h3a2 2 0 0 1 2 2v3m8 0v-3a2 2 0 0 1 2-2h3"
/>
</svg>
</summary>
<div class="disclosure-settings-more">
<label class="visually-hidden" for="radius-bottom-x"
>Bottom radius X</label
>
<input id="radius-bottom-x" type="number" value="0" />
<label class="visually-hidden" for="radius-bottom-y"
>Bottom radius Y</label
>
<input id="radius-bottom-y" type="number" value="0" />
</div>
</details>
</div>
</section>
</section>
</div>
</section>
<section
class="disclosure-workflow disclosure-workflow-wide"
aria-labelledby="disclosure-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="disclosure-rtl-heading">من اليمين إلى اليسار</h2>
<details class="disclosure">
<summary>
<header>
<h4>الطلب #4189</h4>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="m7 15 5 5 5-5M7 9l5-5 5 5" />
</svg>
<span class="visually-hidden">تبديل التفاصيل</span>
</header>
<p><span>الحالة</span><strong>تم الشحن</strong></p>
</summary>
<section>
<article>
<p><strong>عنوان الشحن</strong></p>
<p>100 Market St, San Francisco</p>
</article>
<article>
<p><strong>العناصر</strong></p>
<p>2x سماعات الاستوديو</p>
</article>
</section>
</details>
</section>
</main>
</body>
</html>
File tree
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Disclosure Compositions</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="disclosure-file-tree">
<main aria-label="Disclosure file tree composition">
<div size="sm" class="disclosure-file-card visual-example card">
<header>
<section ng-tabs>
<menu aria-label="File views">
<button aria-selected="true">Explorer</button>
<button>Outline</button>
</menu>
<section>
<span class="visually-hidden">Explorer file tree</span>
</section>
<section>
<span class="visually-hidden">No outline available</span>
</section>
</section>
</header>
<section>
<div class="disclosure-file-tree">
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>components</span>
</summary>
<div>
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>ui</span>
</summary>
<div>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>button.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>card.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>dialog.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>input.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>select.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>table.tsx
</button>
</div>
</details>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>login-form.tsx
</button>
<button variant="link" size="sm">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
/>
<path d="M14 2v6h6" /></svg
>register-form.tsx
</button>
</div>
</details>
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>lib</span>
</summary>
<div>
<button variant="link" size="sm">utils.ts</button
><button variant="link" size="sm">cn.ts</button
><button variant="link" size="sm">api.ts</button>
</div>
</details>
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>hooks</span>
</summary>
<div>
<button variant="link" size="sm">use-media-query.ts</button
><button variant="link" size="sm">use-debounce.ts</button
><button variant="link" size="sm">use-local-storage.ts</button>
</div>
</details>
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>types</span>
</summary>
<div>
<button variant="link" size="sm">index.d.ts</button
><button variant="link" size="sm">api.d.ts</button>
</div>
</details>
<details class="disclosure">
<summary>
<svg
class="tree-chevron"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" /></svg
><svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 19V5a2 2 0 0 1 2-2h5l2 3h5a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z"
/></svg
><span>public</span>
</summary>
<div>
<button variant="link" size="sm">favicon.ico</button
><button variant="link" size="sm">logo.svg</button
><button variant="link" size="sm">images</button>
</div>
</details>
<button variant="link" size="sm">app.tsx</button>
<button variant="link" size="sm">layout.tsx</button>
<button variant="link" size="sm">globals.css</button>
<button variant="link" size="sm">package.json</button>
<button variant="link" size="sm">tsconfig.json</button>
<button variant="link" size="sm">README.md</button>
<button variant="link" size="sm">.gitignore</button>
</div>
</section>
</div>
</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 details and summary disclosure.
Anatomy
Root styling selector
Semantic structure
Apply .disclosure to a native details element with a direct summary followed by authored content. No nested AngularCSS attributes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
open | Authored | Initial or controlled open state. |
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
Native details and summary own disclosure, focus, and keyboard behavior. Use open for initial state and AngularTS only when application state must observe or control the native element. AngularCSS registers no disclosure directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a direct summary as the accessible trigger. The browser exposes disclosure state and provides Enter and Space activation without authored roles or ARIA state.
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.12 - empty
Empty state layout
Empty states compose media, title, description, and action content parts.
<section class="empty">
<header>
<figure variant="icon"></figure>
<h2>No projects yet</h2>
<p>Create your first project.</p>
</header>
</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 Empty</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="empty-demo">
<section class="visual-example empty" aria-live="polite">
<header>
<figure variant="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.75"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 9.75h16.5m-13.5 0V6.75A2.25 2.25 0 0 1 9 4.5h6a2.25 2.25 0 0 1 2.25 2.25v3m-12 0 1.2 8.4A2.25 2.25 0 0 0 8.68 20.25h6.64a2.25 2.25 0 0 0 2.23-2.1l1.2-8.4"
/>
</svg>
</figure>
<h2>No Projects Yet</h2>
<p>
You haven't created any projects yet. Get started by creating your
first project.
</p>
</header>
<section>
<div class="row">
<button>Create Project</button>
<button variant="outline">Import Project</button>
</div>
</section>
<a class="empty-learn-more" href="#learn-more">
Learn More
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M7 17 17 7M7 7h10v10"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</a>
</section>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Empty 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="emptyQuery='';emptyAction='Ready'"
>
<main class="empty-workflow-grid" aria-label="Empty state workflows">
<section data-example="empty-avatar" class="empty-workflow empty">
<header>
<figure>
<span class="empty-avatar-large avatar"
><img src="../../images/avatars/01.png" alt="Jane Doe" /><span
>JD</span
></span
>
</figure>
<h2>User Offline</h2>
<p>
This user is currently offline. Leave a message or try again later.
</p>
</header>
<section>
<button
size="sm"
type="button"
ng-click="emptyAction='Message queued'"
>
Leave Message
</button>
</section>
</section>
<section data-example="empty-avatar-group" class="empty-workflow empty">
<header>
<figure class="empty-avatar-group">
<span class="avatar"
><img src="../../images/avatars/01.png" alt="Jane" /></span
><span class="avatar"
><img src="../../images/avatars/02.png" alt="Alex" /></span
><span class="avatar"
><img src="../../images/avatars/03.png" alt="Sam"
/></span>
</figure>
<h2>No Team Members</h2>
<p>Invite your team to collaborate on this project.</p>
</header>
<section>
<button
size="sm"
type="button"
ng-click="emptyAction='Invite opened'"
>
+ Invite Members
</button>
</section>
</section>
<section
data-example="empty-background"
class="empty-workflow empty-muted-demo empty"
>
<header>
<figure variant="icon">!</figure>
<h2>No Notifications</h2>
<p>You're all caught up. New notifications will appear here.</p>
</header>
<section>
<button
variant="outline"
type="button"
ng-click="emptyAction='Refreshed'"
>
Refresh
</button>
</section>
</section>
<section
data-example="empty-card"
class="empty-workflow empty-card-demo empty"
>
<header>
<figure variant="icon">□</figure>
<h2>No projects yet</h2>
<p>
You haven't created any projects yet. Create your first project.
</p>
</header>
<section>
<div class="row">
<button type="button" ng-click="emptyAction='Create project'">
Create project</button
><button
variant="outline"
type="button"
ng-click="emptyAction='Import project'"
>
Import project
</button>
</div>
<a href="#learn">Learn more</a>
</section>
</section>
<section data-example="empty-input-group" class="empty-workflow empty">
<header>
<h2>404 - Not Found</h2>
<p>The page you're looking for doesn't exist. Try searching below.</p>
</header>
<section>
<div class="input-group">
<input
ng-model="emptyQuery"
placeholder="Try searching for pages..."
aria-label="Search missing pages"
/>
<div>⌕</div>
<div align="inline-end">
<kbd>/</kbd>
</div>
</div>
<p>Need help? <a href="#support">Contact support</a></p>
</section>
</section>
<section
data-example="empty-outline"
class="empty-workflow empty-outline-demo empty"
>
<header>
<figure variant="icon">☁</figure>
<h2>Cloud Storage Empty</h2>
<p>Upload files to access them anywhere.</p>
</header>
<section>
<button
variant="outline"
size="sm"
type="button"
ng-click="emptyAction='Upload opened'"
>
Upload Files
</button>
</section>
</section>
<section
data-example="empty-rtl"
class="empty-workflow empty"
dir="rtl"
lang="ar"
>
<header>
<figure variant="icon">□</figure>
<h2>لا توجد مشاريع بعد</h2>
<p>لم تقم بإنشاء أي مشاريع بعد. ابدأ بإنشاء مشروعك الأول.</p>
</header>
<section>
<div class="row">
<button type="button" ng-click="emptyAction='إنشاء مشروع'">
إنشاء مشروع</button
><button
variant="outline"
type="button"
ng-click="emptyAction='استيراد مشروع'"
>
استيراد مشروع
</button>
</div>
</section>
</section>
<output class="empty-workflow-output">
{{ emptyAction }} · {{ emptyQuery }}
</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. Semantic empty-state content.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
variant | Authored | Optional direct figure presentation: icon; omit for the default media treatment. |
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
Semantic empty-state content. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
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.
6.13 - field
Group labels, helper text, and errors with semantic field wrapper selectors.
Use the field wrapper and field parts to define standard form structure.
<div class="field">
<label for="email">Email</label>
<input id="email" type="email" placeholder="Email" />
<p>Use your work email.</p>
</div>
<div class="field">
<label for="invalid-email">Email</label>
<input id="invalid-email" aria-invalid="true" />
<p class="field-error">Enter a valid email.</p>
</div>
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 Field</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="name='Jane Doe'; email=''">
<form class="stack">
<fieldset class="field-set">
<legend>Profile</legend>
<div class="field-group">
<div class="field">
<label for="demo-profile-name">Name</label>
<input
id="demo-profile-name"
aria-describedby="demo-profile-name-description"
placeholder="Jane Doe"
ng-model="name"
/>
<p id="demo-profile-name-description">
Use your public display name.
</p>
</div>
<div class="field">
<label for="demo-profile-email"> Email </label>
<input
id="demo-profile-email"
type="email"
placeholder="Enter an email"
required
aria-describedby="demo-profile-email-error"
ng-model="email"
/>
<p
id="demo-profile-email-error"
ng-show="!email"
class="field-error"
>
Enter a valid email.
</p>
</div>
</div>
</fieldset>
<output class="output">
Preview: <span ng-bind="name"></span>
<span ng-bind="email ? '(' + email + ')' : '(email required)'"></span>
</output>
</form>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Field 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="fieldState={username:'',password:'',feedback:'',department:'',hardDisks:true,externalDisks:false,cds:false,servers:false,sync:true,twoFactor:false,plan:'monthly',environment:'kubernetes',minimum:200,maximum:800,street:'',city:'',zip:'',push:true,pushTasks:false,emailTasks:false,profileName:'',message:'Ready',sameAsShipping:true,month:'',year:''}"
>
<main class="field-workflow-grid" aria-label="Field workflows">
<section data-example="field-input" class="field-workflow">
<fieldset class="field-set">
<div class="field-group">
<div class="field">
<label for="field-username">Username</label
><input
id="field-username"
ng-model="fieldState.username"
placeholder="Max Leiter"
/>
<p>Choose a unique username for your account.</p>
</div>
<div class="field">
<label for="field-password">Password</label>
<p>Must be at least 8 characters long.</p>
<input
id="field-password"
type="password"
ng-model="fieldState.password"
placeholder="••••••••"
/>
</div>
</div>
</fieldset>
</section>
<section data-example="field-textarea" class="field-workflow">
<fieldset class="field-set">
<div class="field-group">
<div class="field">
<label for="field-feedback">Feedback</label
><textarea
id="field-feedback"
ng-model="fieldState.feedback"
placeholder="Your feedback helps us improve..."
rows="4"
></textarea>
<p>Share your thoughts about our service.</p>
</div>
</div>
</fieldset>
</section>
<section data-example="field-select" class="field-workflow">
<div class="field">
<label for="field-department">Department</label>
<select id="field-department" ng-model="fieldState.department">
<option value="">Choose department</option>
<option>Engineering</option>
<option>Design</option>
<option>Marketing</option>
<option>Sales</option>
<option>Customer Support</option>
</select>
<p>Select your department or area of work.</p>
</div>
</section>
<section data-example="field-checkbox" class="field-workflow">
<div class="field-group">
<fieldset class="field-set">
<legend variant="label">Show these items on the desktop</legend>
<p>Select the items you want to show on the desktop.</p>
<div class="field-choice-list checkbox-group">
<div orientation="horizontal" class="field">
<input
id="field-hard-disks"
type="checkbox"
ng-model="fieldState.hardDisks"
/><label for="field-hard-disks">Hard disks</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-external-disks"
type="checkbox"
ng-model="fieldState.externalDisks"
/><label for="field-external-disks">External disks</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-cds"
type="checkbox"
ng-model="fieldState.cds"
/><label for="field-cds">CDs, DVDs, and iPods</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-servers"
type="checkbox"
ng-model="fieldState.servers"
/><label for="field-servers">Connected servers</label>
</div>
</div>
</fieldset>
<hr />
<div orientation="horizontal" class="field">
<input id="field-sync" type="checkbox" ng-model="fieldState.sync" />
<section>
<label for="field-sync"
>Sync Desktop & Documents folders</label
>
<p>Access these folders from your other devices.</p>
</section>
</div>
</div>
</section>
<section data-example="field-switch" class="field-workflow">
<div orientation="horizontal" class="field-switch-demo field">
<label for="field-2fa">Multi-factor authentication</label
><input
role="switch"
id="field-2fa"
type="checkbox"
ng-model="fieldState.twoFactor"
/>
</div>
</section>
<section data-example="field-radio" class="field-workflow">
<fieldset class="field-set field-choice-list">
<legend variant="label">Subscription Plan</legend>
<p>Yearly and lifetime plans offer significant savings.</p>
<div orientation="horizontal" class="field">
<input
id="field-monthly"
name="field-plan"
type="radio"
value="monthly"
ng-model="fieldState.plan"
/><label for="field-monthly">Monthly ($9.99/month)</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-yearly"
name="field-plan"
type="radio"
value="yearly"
ng-model="fieldState.plan"
/><label for="field-yearly">Yearly ($99.99/year)</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-lifetime"
name="field-plan"
type="radio"
value="lifetime"
ng-model="fieldState.plan"
/><label for="field-lifetime">Lifetime ($299.99)</label>
</div>
</fieldset>
</section>
<section data-example="field-slider" class="field-workflow">
<div class="field">
<strong>Price Range</strong>
<p>
Set your budget range (${{ fieldState.minimum }} - ${{
fieldState.maximum }}).
</p>
<div
ng-range-slider
min="0"
max="1000"
aria-label="Price Range"
class="field-slider-demo"
>
<input
type="range"
min="0"
max="1000"
step="10"
ng-model="fieldState.minimum"
aria-label="Minimum budget"
/><input
type="range"
min="0"
max="1000"
step="10"
ng-model="fieldState.maximum"
aria-label="Maximum budget"
/>
</div>
</div>
</section>
<section data-example="field-choice-card" class="field-workflow">
<div class="field-group">
<fieldset class="field-set field-card-list">
<legend variant="label">Compute Environment</legend>
<p>Select the compute environment for your cluster.</p>
<label for="field-kubernetes"
><div orientation="horizontal" class="field">
<section>
<strong>Kubernetes</strong>
<p>Run GPU workloads on a K8s cluster.</p>
</section>
<input
id="field-kubernetes"
name="environment"
type="radio"
value="kubernetes"
ng-model="fieldState.environment"
/></div></label
><label for="field-vm"
><div orientation="horizontal" class="field">
<section>
<strong>Virtual Machine</strong>
<p>Access a cluster to run GPU workloads.</p>
</section>
<input
id="field-vm"
name="environment"
type="radio"
value="vm"
ng-model="fieldState.environment"
/></div
></label>
</fieldset>
</div>
</section>
<section data-example="field-fieldset" class="field-workflow">
<fieldset class="field-set">
<legend>Address Information</legend>
<p>We need your address to deliver your order.</p>
<div class="field-group">
<div class="field">
<label for="field-street">Street Address</label
><input
id="field-street"
ng-model="fieldState.street"
placeholder="123 Main St"
/>
</div>
<div class="field-two-column">
<div class="field">
<label for="field-city">City</label
><input
id="field-city"
ng-model="fieldState.city"
placeholder="New York"
/>
</div>
<div class="field">
<label for="field-zip">Postal Code</label
><input
id="field-zip"
ng-model="fieldState.zip"
placeholder="90502"
/>
</div>
</div>
</div>
</fieldset>
</section>
<section data-example="field-group" class="field-workflow">
<div class="field-group">
<fieldset class="field-set">
<label>Responses</label>
<p>
Get notified when ChatGPT responds to requests that take time.
</p>
<div orientation="horizontal" class="field">
<input
id="field-push"
type="checkbox"
ng-model="fieldState.push"
disabled
/><label for="field-push">Push notifications</label>
</div>
</fieldset>
<hr />
<fieldset class="field-set">
<label>Tasks</label>
<p>
Get notified when tasks have updates.
<a href="#tasks">Manage tasks</a>
</p>
<div class="field-choice-list">
<div orientation="horizontal" class="field">
<input
id="field-push-tasks"
type="checkbox"
ng-model="fieldState.pushTasks"
/><label for="field-push-tasks">Push notifications</label>
</div>
<div orientation="horizontal" class="field">
<input
id="field-email-tasks"
type="checkbox"
ng-model="fieldState.emailTasks"
/><label for="field-email-tasks">Email notifications</label>
</div>
</div>
</fieldset>
</div>
</section>
<section
data-example="field-responsive"
class="field-workflow field-workflow-wide"
>
<form
ng-submit="fieldState.message='Profile submitted '+fieldState.profileName"
>
<fieldset class="field-set">
<legend>Profile</legend>
<p>Fill in your profile information.</p>
<div class="field-group">
<div orientation="responsive" class="field">
<section>
<label for="field-profile-name">Name</label>
<p>Provide your full name for identification</p>
</section>
<input
id="field-profile-name"
ng-model="fieldState.profileName"
placeholder="Evil Rabbit"
required
/>
</div>
<div orientation="responsive" class="field-form-actions field">
<button type="submit">Submit</button
><button
type="button"
variant="outline"
ng-click="fieldState.message='Cancelled'"
>
Cancel
</button>
</div>
</div>
</fieldset>
</form>
</section>
<section
data-example="field-demo"
class="field-workflow field-workflow-wide"
>
<form ng-submit="fieldState.message='Payment submitted'">
<div class="field-group">
<fieldset class="field-set">
<legend>Payment Method</legend>
<p>All transactions are secure and encrypted</p>
<div class="field-group">
<div class="field">
<label for="field-card-name">Name on Card</label
><input
id="field-card-name"
placeholder="Evil Rabbit"
required
/>
</div>
<div class="field">
<label for="field-card-number">Card Number</label
><input
id="field-card-number"
placeholder="1234 5678 9012 3456"
required
/>
<p>Enter your 16-digit card number</p>
</div>
<div class="field-three-column">
<div class="field">
<label for="field-month">Month</label
><input id="field-month" placeholder="MM" />
</div>
<div class="field">
<label for="field-year">Year</label
><input id="field-year" placeholder="YYYY" />
</div>
<div class="field">
<label for="field-cvv">CVV</label
><input id="field-cvv" placeholder="123" required />
</div>
</div>
</div>
</fieldset>
<hr />
<fieldset class="field-set">
<legend>Billing Address</legend>
<p>The billing address associated with your payment method</p>
<div orientation="horizontal" class="field">
<input
id="field-same-shipping"
type="checkbox"
ng-model="fieldState.sameAsShipping"
/><label for="field-same-shipping"
>Same as shipping address</label
>
</div>
</fieldset>
<fieldset class="field-set">
<div class="field">
<label for="field-comments">Comments</label
><textarea
id="field-comments"
placeholder="Add any additional comments"
></textarea>
</div>
</fieldset>
<div orientation="horizontal" class="field-form-actions field">
<button type="submit">Submit</button
><button type="button" variant="outline">Cancel</button>
</div>
</div>
</form>
</section>
<section
data-example="field-rtl"
class="field-workflow field-workflow-wide"
dir="rtl"
lang="ar"
>
<form>
<div class="field-group">
<fieldset class="field-set">
<legend>طريقة الدفع</legend>
<p>جميع المعاملات آمنة ومشفرة</p>
<div class="field-group">
<div class="field">
<label for="field-card-name-rtl">الاسم على البطاقة</label
><input id="field-card-name-rtl" placeholder="Evil Rabbit" />
</div>
<div class="field">
<label for="field-card-number-rtl">رقم البطاقة</label
><input
id="field-card-number-rtl"
placeholder="1234 5678 9012 3456"
/>
<p>أدخل رقم البطاقة المكون من 16 رقمًا</p>
</div>
<div class="field-three-column">
<div class="field">
<label>الشهر</label><input placeholder="ش.ش" />
</div>
<div class="field">
<label>السنة</label><input placeholder="YYYY" />
</div>
<div class="field">
<label>CVV</label><input placeholder="123" />
</div>
</div>
</div>
</fieldset>
<hr />
<div orientation="horizontal" class="field">
<input
id="field-same-shipping-rtl"
type="checkbox"
checked
/><label for="field-same-shipping-rtl">نفس عنوان الشحن</label>
</div>
<div class="field">
<label for="field-comments-rtl">تعليقات</label
><textarea
id="field-comments-rtl"
placeholder="أضف أي تعليقات إضافية"
></textarea>
</div>
<div orientation="horizontal" class="field-form-actions field">
<button type="button">إرسال</button
><button type="button" variant="outline">إلغاء</button>
</div>
</div>
</form>
</section>
<output class="field-workflow-output"> {{ fieldState.message }} </output>
</main>
</body>
</html>
Validation States
Fields derive presentation from native validity and aria-invalid; AngularTS
structural directives may insert or remove controls and descriptions.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Field State 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="state={requiredEmail:'',dynamicVisible:false}"
>
<form class="component-state-grid" aria-label="Field state contracts">
<section
class="component-state-section"
aria-labelledby="field-messages-title"
>
<h2 id="field-messages-title">Messages</h2>
<div id="message-field" class="field">
<label for="message-control">Name</label>
<input
id="message-control"
aria-describedby="message-description message-error"
/>
<p id="message-description">Use your public display name.</p>
<p id="message-error" class="field-error">
The display name is already in use.
</p>
</div>
</section>
<section
class="component-state-section"
aria-labelledby="field-invalid-title"
>
<h2 id="field-invalid-title">Invalid state</h2>
<div id="explicit-invalid-field" class="field">
<label for="explicit-invalid-control"> Workspace </label>
<input id="explicit-invalid-control" aria-invalid="true" />
</div>
</section>
<section
class="component-state-section"
aria-labelledby="field-required-title"
>
<h2 id="field-required-title">Native validation</h2>
<div id="required-field" class="field">
<label for="required-email">Email</label>
<input
id="required-email"
type="email"
required
ng-model="state.requiredEmail"
/>
</div>
</section>
<section
class="component-state-section"
aria-labelledby="field-dynamic-title"
>
<h2 id="field-dynamic-title">Conditional control</h2>
<div id="dynamic-field" class="field">
<label for="dynamic-email">Team email</label>
<p id="dynamic-email-description">Use the address for your team.</p>
<input
ng-if="state.dynamicVisible"
id="dynamic-email"
type="email"
aria-describedby="dynamic-email-description"
required
/>
</div>
<button
variant="outline"
type="button"
ng-click="state.dynamicVisible=true"
ng-disabled="state.dynamicVisible"
>
Add email field
</button>
</section>
</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. Native labels, descriptions, and validation.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
orientation | Authored | Field layout: horizontal or responsive; omit for the vertical layout. |
variant | Authored | Compact label typography when authored on a fieldset legend. |
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
Field is a styling-only semantic form composition. Native labels, validation, and aria-describedby own relationships; AngularTS forms and structural directives own model, error visibility, and submission state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Connect every control to a native label. Give descriptions and errors stable IDs and author aria-describedby on the control. Use native fieldset and legend only for actual groups of related controls.
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.14 - file-upload
Native file selection and transfer status
Keep file selection native and present application-owned queue and progress
state beside it. AngularTS can handle drop events and backend transfer commands
without introducing a second upload 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 File Upload</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="file-upload-demo">
<section class="visual-example" aria-labelledby="upload-title">
<header>
<h2 id="upload-title">Supporting documents</h2>
<p>PDF, PNG, or JPG files up to 10 MB.</p>
</header>
<label for="supporting-files">
<strong>Choose files or drop them here</strong>
<span>The application validates and transfers selected files.</span>
<input
id="supporting-files"
type="file"
accept=".pdf,image/png,image/jpeg"
multiple
/>
</label>
<ul aria-label="Upload queue">
<li>
<span>contract.pdf</span>
<output>72%</output>
<progress value="72" max="100">72%</progress>
</li>
</ul>
<output aria-live="polite">1 file ready for processing</output>
</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. Native file input and authored status.
Anatomy
Root styling selector
section:has(> label > input[type="file"])
Semantic structure
Use a semantic section with a direct label containing a native file input. Optional direct ul, native progress, and output elements present application-owned queue and transfer state without component or part classes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
accept | Authored | Native accepted file types on the direct file input. |
dragging | Authored | Presentational drop-target state on the root section. |
multiple | Authored | Allows the direct native file input to accept several files. |
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
File Upload styles a native file input, authored queue, native progress, and status output. AngularTS or the application owns drag-and-drop event handling, validation, transfer, retry, cancellation, and persistence.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Keep the native file input operable and labeled. Announce queue changes with a status output, label progress, and expose validation or transfer errors as text rather than color alone.
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.15 - filter-bar
Search and filter controls for data views
Use a native form to collect a data view’s search and filter values. Submit,
reset, AngularTS binding, and backend queries keep their existing ownership.
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 Filter Bar</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="filter-bar-demo">
<main class="visual-example">
<form role="search" aria-label="Filter orders">
<fieldset>
<legend class="visually-hidden">Order filters</legend>
<label>
Search
<input type="search" name="query" placeholder="Order or customer" />
</label>
<label>
Status
<select name="status">
<option value="">All statuses</option>
<option>Open</option>
<option>Complete</option>
</select>
</label>
</fieldset>
<menu>
<button variant="outline" type="reset">Reset</button>
<button type="submit">Apply</button>
</menu>
</form>
</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. Semantic search and filter form.
Anatomy
Root styling selector
form[role="search"]:has(> fieldset + menu)
Semantic structure
Use role="search" on a native form with a direct fieldset followed by a direct action menu. Put labeled controls in the fieldset and submit or reset actions in the menu.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
role | Authored | Explicit semantic role when native HTML does not provide one. |
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
Filter Bar is a native form composition. The browser and AngularTS own control values and submission; the backend may remain authoritative for queries, result counts, and pagination.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native form and fieldset with accessible labels. Submit applies the query, reset restores defaults, and result changes should be announced near the results they affect.
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.16 - input-group
Grouped input controls and addon content with shared focus/description wiring.
Use .input-group with one native control and optional authored addons, text,
and buttons. AngularTS continues to own the model and actions.
<div class="input-group">
<input id="search" placeholder="Search" />
<label for="search" align="inline-start">Search</label>
<div align="inline-end">⌘K</div>
</div>
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 Input Group</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>
<main class="stack">
<div class="field">
<label for="search">Search</label>
<div class="input-group">
<input id="search" placeholder="Search documentation..." />
<label for="search" align="inline-start">
<span aria-hidden="true">⌕</span>
</label>
</div>
</div>
</main>
</body>
</html>
Reference Workflows
These packaged examples cover default, disabled, invalid, inline, text, icon,
keyboard-hint, label, Button Group, and Card compositions.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Input Group 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="query=''; message=''; copyStatus='Ready'; cardStatus=''; username='angularcss'"
data-example="input-group-workflows"
>
<svg class="example-icon-definitions" aria-hidden="true">
<defs>
<symbol id="ig-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</symbol>
<symbol id="ig-mail" viewBox="0 0 24 24">
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
<path d="m22 7-10 6L2 7"></path>
</symbol>
<symbol id="ig-card" viewBox="0 0 24 24">
<rect width="20" height="14" x="2" y="5" rx="2"></rect>
<path d="M2 10h20"></path>
</symbol>
<symbol id="ig-check" viewBox="0 0 24 24">
<path d="m5 12 4 4L19 6"></path>
</symbol>
<symbol id="ig-eye-off" viewBox="0 0 24 24">
<path d="m2 2 20 20"></path>
<path
d="M6.7 6.7C4.8 8 3.3 9.8 2.5 12c1.5 4 5.2 7 9.5 7 1.5 0 2.9-.3 4.1-.9"
></path>
<path
d="M10.7 5.1A10 10 0 0 1 12 5c4.3 0 8 3 9.5 7a10.8 10.8 0 0 1-2.1 3.4"
></path>
</symbol>
<symbol id="ig-star" viewBox="0 0 24 24">
<path
d="m12 2 3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.2L5.8 21 7 14.2 2 9.3l6.9-1Z"
></path>
</symbol>
<symbol id="ig-info" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4M12 8h.01"></path>
</symbol>
<symbol id="ig-link" viewBox="0 0 24 24">
<path
d="M10 13a5 5 0 0 0 7.1.1l2-2a5 5 0 0 0-7.1-7.1l-1.1 1.1"
></path>
<path d="M14 11a5 5 0 0 0-7.1-.1l-2 2A5 5 0 0 0 12 20l1.1-1.1"></path>
</symbol>
</defs>
</svg>
<main class="input-group-workflow-grid" aria-label="Input group examples">
<section
class="input-group-workflow"
data-example="input-group-basic"
aria-labelledby="input-group-basic-title"
>
<h2 id="input-group-basic-title">States</h2>
<div class="field-group">
<div class="field">
<label for="ig-default">Default</label>
<input id="ig-default" placeholder="Placeholder" />
</div>
<div class="field">
<label for="ig-basic">Input group</label>
<div class="input-group">
<input id="ig-basic" placeholder="Placeholder" />
</div>
</div>
<div class="field">
<label for="ig-disabled">Disabled</label>
<div class="input-group">
<input
id="ig-disabled"
placeholder="This field is disabled"
disabled
/>
</div>
</div>
<div class="field">
<label for="ig-invalid">Invalid</label>
<div class="input-group">
<input
id="ig-invalid"
placeholder="This field is invalid"
aria-invalid="true"
/>
</div>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-demo input-group-inline-start input-group-inline-end input-group-kbd"
aria-labelledby="input-group-position-title"
>
<h2 id="input-group-position-title">Inline addons</h2>
<div class="input-group">
<input
ng-model="query"
placeholder="Search..."
aria-label="Search documentation"
/>
<div align="inline-start">
<svg aria-hidden="true"><use href="#ig-search"></use></svg>
</div>
<div align="inline-end">{{ query ? '12 results' : 'No query' }}</div>
</div>
<div class="input-group">
<input
type="password"
placeholder="Enter password"
aria-label="Password"
/>
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-eye-off"></use></svg>
</div>
</div>
<div class="input-group">
<input id="ig-command-search" placeholder="Search commands..." />
<label for="ig-command-search">
<svg aria-hidden="true"><use href="#ig-search"></use></svg>
</label>
<div align="inline-end">
<kbd>⌘K</kbd>
</div>
</div>
<output class="input-group-output">
Query: {{ query || 'none' }}
</output>
</section>
<section
class="input-group-workflow"
data-example="input-group-icon"
aria-labelledby="input-group-icon-title"
>
<h2 id="input-group-icon-title">Icons</h2>
<div class="input-group">
<input
type="email"
placeholder="Enter your email"
aria-label="Email with icon"
/>
<div>
<svg aria-hidden="true"><use href="#ig-mail"></use></svg>
</div>
</div>
<div class="input-group">
<input placeholder="Card number" aria-label="Verified card number" />
<div>
<svg aria-hidden="true"><use href="#ig-card"></use></svg>
</div>
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-check"></use></svg>
</div>
</div>
<div class="input-group">
<input placeholder="Favorite card" aria-label="Favorite card" />
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-star"></use></svg>
<svg aria-hidden="true"><use href="#ig-info"></use></svg>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-text"
aria-labelledby="input-group-text-title"
>
<h2 id="input-group-text-title">Text addons</h2>
<div class="input-group">
<div>
<span>$</span>
</div>
<input inputmode="decimal" placeholder="0.00" aria-label="Amount" />
<div align="inline-end">
<span>USD</span>
</div>
</div>
<div class="input-group">
<div>
<span>https://</span>
</div>
<input placeholder="example.com" aria-label="Website" />
<div align="inline-end">
<span>.com</span>
</div>
</div>
<div class="input-group">
<input
placeholder="Enter your username"
aria-label="Company username"
/>
<div align="inline-end">
<span>@company.com</span>
</div>
</div>
</section>
<section
class="input-group-workflow input-group-workflow-wide"
data-example="input-group-with-addons"
aria-labelledby="input-group-addons-title"
>
<h2 id="input-group-addons-title">Addon positions</h2>
<div class="input-group-pair-grid">
<div class="field">
<label for="ig-addon-start">Inline start and end</label>
<div class="input-group">
<input id="ig-addon-start" />
<div>
<svg aria-hidden="true"><use href="#ig-search"></use></svg>
</div>
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-info"></use></svg>
</div>
</div>
</div>
<div class="field">
<label for="ig-addon-header">Block start</label>
<div class="input-group">
<input id="ig-addon-header" />
<div align="block-start">
<span>First name</span>
<svg class="input-group-push-end" aria-hidden="true">
<use href="#ig-info"></use>
</svg>
</div>
</div>
</div>
<div class="field">
<label for="ig-addon-footer">Block end</label>
<div class="input-group">
<input id="ig-addon-footer" />
<div align="block-end">
<span>20/240 characters</span>
<svg class="input-group-push-end" aria-hidden="true">
<use href="#ig-info"></use>
</svg>
</div>
</div>
</div>
<div class="field">
<label for="ig-addon-optional">Label and optional text</label>
<div class="input-group">
<div>
<label for="ig-addon-optional">Label</label>
</div>
<input id="ig-addon-optional" />
<div align="inline-end">
<span>(optional)</span>
</div>
</div>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-with-kbd"
aria-labelledby="input-group-kbd-title"
>
<h2 id="input-group-kbd-title">Keyboard hints</h2>
<div class="input-group">
<input placeholder="Search for apps..." aria-label="Search apps" />
<div align="inline-end">Ask AI</div>
<div align="inline-end">
<kbd>Tab</kbd>
</div>
</div>
<div class="input-group">
<input ng-model="username" aria-label="Username" />
<div align="inline-end">
<span class="input-group-valid-icon"
><svg aria-hidden="true"><use href="#ig-check"></use></svg
></span>
</div>
</div>
<p class="input-group-success">This username is available.</p>
<div class="input-group">
<input value="angularcss" aria-label="Loading username" disabled />
<div align="inline-end">
<output size="sm" aria-label="Loading" class="spinner"></output>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-label"
aria-labelledby="input-group-label-title"
>
<h2 id="input-group-label-title">Labels in addons</h2>
<div class="input-group">
<input id="ig-email-name" placeholder="angularcss" />
<div>
<label for="ig-email-name">@</label>
</div>
</div>
<div class="input-group">
<input id="ig-email-address" placeholder="team@angularcss.dev" />
<div align="block-start">
<label for="ig-email-address">Email</label>
<span ng-tooltip class="input-group-push-end">
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Email help"
>
<svg aria-hidden="true"><use href="#ig-info"></use></svg>
</button>
<span side="top">We'll use this to send notifications.</span>
</span>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-button-group"
aria-labelledby="input-group-button-group-title"
>
<h2 id="input-group-button-group-title">Button group</h2>
<div role="group">
<label for="ig-url">https://</label>
<div class="input-group">
<input id="ig-url" aria-label="URL" />
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-link"></use></svg>
</div>
</div>
<span>.com</span>
</div>
</section>
<section
class="input-group-workflow input-group-card-workflow"
data-example="input-group-in-card"
aria-labelledby="input-group-card-title"
>
<article class="card">
<header>
<h2 id="input-group-card-title">Card with input group</h2>
<p>Collect contact details and feedback.</p>
</header>
<section>
<div class="field-group">
<div class="field">
<label for="ig-card-email">Email address</label>
<div class="input-group">
<input
id="ig-card-email"
type="email"
placeholder="you@example.com"
/>
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-mail"></use></svg>
</div>
</div>
</div>
<div class="field">
<label for="ig-card-site">Website URL</label>
<div class="input-group">
<div>
<span>https://</span>
</div>
<input id="ig-card-site" placeholder="example.com" />
<div align="inline-end">
<svg aria-hidden="true"><use href="#ig-link"></use></svg>
</div>
</div>
</div>
</div>
</section>
<footer class="input-group-card-actions">
<button
variant="outline"
type="button"
ng-click="cardStatus='Cancelled'"
>
Cancel
</button>
<button type="button" ng-click="cardStatus='Submitted'">
Submit
</button>
<output class="input-group-output">{{ cardStatus }}</output>
</footer>
</article>
</section>
</main>
</body>
</html>
Interactive Compositions
Buttons, dropdown menus, tooltips, popovers, calling-code selection, and mixed
Button Group compositions run from AngularTS bindings in the built artifact.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Input Group Compositions</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="copied=false; favorite=false; country='+1'; compositionStatus='Ready'"
data-example="input-group-compositions"
>
<svg class="example-icon-definitions" aria-hidden="true">
<defs>
<symbol id="igc-copy" viewBox="0 0 24 24">
<rect width="14" height="14" x="8" y="8" rx="2"></rect>
<path
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
></path>
</symbol>
<symbol id="igc-check" viewBox="0 0 24 24">
<path d="m5 12 4 4L19 6"></path>
</symbol>
<symbol id="igc-star" viewBox="0 0 24 24">
<path
d="m12 2 3.1 6.3 6.9 1-5 4.9 1.2 6.8-6.2-3.2L5.8 21 7 14.2 2 9.3l6.9-1Z"
></path>
</symbol>
<symbol id="igc-info" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4M12 8h.01"></path>
</symbol>
<symbol id="igc-help" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"></circle>
<path d="M9.1 9a3 3 0 1 1 5.8 1c0 2-3 2-3 4M12 18h.01"></path>
</symbol>
<symbol id="igc-more" viewBox="0 0 24 24">
<circle cx="5" cy="12" r="1"></circle>
<circle cx="12" cy="12" r="1"></circle>
<circle cx="19" cy="12" r="1"></circle>
</symbol>
<symbol id="igc-chevron" viewBox="0 0 24 24">
<path d="m6 9 6 6 6-6"></path>
</symbol>
<symbol id="igc-trash" viewBox="0 0 24 24">
<path d="M3 6h18M8 6V4h8v2M19 6l-1 16H6L5 6M10 11v6M14 11v6"></path>
</symbol>
</defs>
</svg>
<main
class="input-group-composition-grid"
aria-label="Interactive input group compositions"
>
<section
class="input-group-workflow"
data-example="input-group-button"
aria-labelledby="igc-button-title"
>
<h2 id="igc-button-title">Buttons</h2>
<div class="input-group">
<input
value="https://x.com/angularcss"
aria-label="Share URL"
readonly
/>
<div align="inline-end">
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Copy URL"
ng-click="copied=true; compositionStatus='Copied URL'"
>
<svg aria-hidden="true">
<use ng-if="!copied" href="#igc-copy"></use>
<use ng-if="copied" href="#igc-check"></use>
</svg>
</button>
</div>
</div>
<div class="input-group-pill input-group">
<span>
<button
size="icon-xs"
variant="secondary"
type="button"
aria-label="Connection information"
popovertarget="popover-input-group-compositions-1-content"
>
<svg aria-hidden="true"><use href="#igc-info"></use></svg>
</button>
<aside
class="input-group-popover-content"
aria-label="Connection status"
id="popover-input-group-compositions-1-content"
side="bottom"
align="start"
popover
>
<strong>Your connection is not secure.</strong>
<p>You should not enter sensitive information on this site.</p>
</aside>
</span>
<div>https://</div>
<input aria-label="Secure URL" />
<div align="inline-end">
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Favorite URL"
aria-pressed="{{ favorite }}"
ng-click="favorite=!favorite; compositionStatus=favorite ? 'Added favorite' : 'Removed favorite'"
>
<svg aria-hidden="true">
<use href="#igc-star"></use>
</svg>
</button>
</div>
</div>
<div class="input-group">
<input placeholder="Type to search..." aria-label="Search query" />
<div align="inline-end">
<button
variant="secondary"
type="button"
ng-click="compositionStatus='Search submitted'"
>
Search
</button>
</div>
</div>
<output class="input-group-output">{{ compositionStatus }}</output>
</section>
<section
class="input-group-workflow"
data-example="input-group-with-buttons"
aria-labelledby="igc-variants-title"
>
<h2 id="igc-variants-title">Button variants</h2>
<div class="input-group">
<input aria-label="Default action" />
<div>
<button type="button" ng-click="compositionStatus='Default action'">
Default
</button>
</div>
</div>
<div class="input-group">
<input aria-label="Outline action" />
<div>
<button
variant="outline"
type="button"
ng-click="compositionStatus='Outline action'"
>
Outline
</button>
</div>
</div>
<div class="input-group">
<input aria-label="Secondary action" />
<div align="inline-end">
<button
variant="secondary"
type="button"
ng-click="compositionStatus='Secondary action'"
>
Button
</button>
</div>
</div>
<div class="input-group">
<input aria-label="Delete action" />
<div align="inline-end">
<button
size="icon-xs"
variant="secondary"
type="button"
aria-label="Delete"
ng-click="compositionStatus='Deleted'"
>
<svg aria-hidden="true"><use href="#igc-trash"></use></svg>
</button>
</div>
</div>
</section>
<section
class="input-group-workflow input-group-menu-workflow"
data-example="input-group-dropdown"
aria-labelledby="igc-dropdown-title"
>
<h2 id="igc-dropdown-title">Dropdown menus</h2>
<div class="input-group">
<input placeholder="Enter file name" aria-label="File name" />
<div align="inline-end">
<span ng-dropdown-menu class="input-group-overlay-control">
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="File options"
>
<svg aria-hidden="true"><use href="#igc-more"></use></svg>
</button>
<menu align="end" style="--menu-width: 10rem">
<button ng-click="compositionStatus='Settings'">
Settings
</button>
<button ng-click="compositionStatus='Copied path'">
Copy path
</button>
<button ng-click="compositionStatus='Opened location'">
Open location
</button>
</menu>
</span>
</div>
</div>
<div class="input-group">
<input
placeholder="Enter search query"
aria-label="Search query with scope"
/>
<div align="inline-end">
<span ng-dropdown-menu class="input-group-overlay-control">
<button variant="ghost" type="button">
Search in
<svg aria-hidden="true"><use href="#igc-chevron"></use></svg>
</button>
<menu align="end" style="--menu-width: 10rem">
<button ng-click="compositionStatus='Documentation'">
Documentation
</button>
<button ng-click="compositionStatus='Blog posts'">
Blog posts
</button>
<button ng-click="compositionStatus='Changelog'">
Changelog
</button>
</menu>
</span>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-tooltip"
aria-labelledby="igc-tooltip-title"
>
<h2 id="igc-tooltip-title">Tooltips</h2>
<div class="input-group">
<input
type="password"
placeholder="Enter password"
aria-label="Password requirements"
/>
<div align="inline-end">
<span ng-tooltip>
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Password information"
>
<svg aria-hidden="true"><use href="#igc-info"></use></svg>
</button>
<span side="top">Password must be at least 8 characters.</span>
</span>
</div>
</div>
<div class="input-group">
<input
placeholder="Your email address"
aria-label="Notification email"
/>
<div align="inline-end">
<span ng-tooltip>
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Email help"
>
<svg aria-hidden="true"><use href="#igc-help"></use></svg>
</button>
<span side="top">We'll use this to send notifications.</span>
</span>
</div>
</div>
<div class="input-group">
<input placeholder="Enter API key" aria-label="API key" />
<div align="inline-end">
<span ng-tooltip>
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="API key help"
>
<svg aria-hidden="true"><use href="#igc-help"></use></svg>
</button>
<span side="left">Click for help with API keys.</span>
</span>
</div>
</div>
</section>
<section
class="input-group-workflow input-group-workflow-wide"
data-example="input-group-with-tooltip"
aria-labelledby="igc-mixed-title"
>
<h2 id="igc-mixed-title">Mixed interactive controls</h2>
<div class="input-group-pair-grid">
<div class="field">
<label for="igc-tooltip-input">Tooltip</label>
<div class="input-group">
<input id="igc-tooltip-input" />
<div align="inline-end">
<span ng-tooltip
><button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Input information"
>
<svg aria-hidden="true">
<use href="#igc-info"></use>
</svg></button
><span side="top">This is content in a tooltip.</span></span
>
</div>
</div>
<p>This is a description of the input group.</p>
</div>
<div class="field">
<label for="igc-country-input">Dropdown</label>
<div class="input-group">
<input id="igc-country-input" type="tel" />
<div>
<span ng-dropdown-menu class="input-group-overlay-control">
<button variant="ghost" type="button">
{{ country }}
<svg aria-hidden="true">
<use href="#igc-chevron"></use>
</svg>
</button>
<menu align="end" style="--menu-width: 5rem">
<button ng-click="country='+1'">+1</button>
<button ng-click="country='+44'">+44</button>
<button ng-click="country='+46'">+46</button>
</menu>
</span>
</div>
</div>
<p>Select a calling code.</p>
</div>
<div class="field">
<label for="igc-popover-input">Popover</label>
<div class="input-group">
<span>
<button
size="icon-xs"
variant="secondary"
type="button"
aria-label="Security details"
popovertarget="popover-input-group-compositions-2-content"
>
<svg aria-hidden="true"><use href="#igc-info"></use></svg>
</button>
<aside
class="input-group-popover-content"
aria-label="Security details"
id="popover-input-group-compositions-2-content"
side="bottom"
align="start"
popover
>
<strong>Your connection is not secure.</strong>
<p>Do not enter sensitive information on this site.</p>
</aside>
</span>
<div>https://</div>
<input id="igc-popover-input" />
<div align="inline-end">
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Add favorite"
ng-click="compositionStatus='Added to favorites'"
>
<svg aria-hidden="true"><use href="#igc-star"></use></svg>
</button>
</div>
</div>
</div>
<div class="field">
<label for="igc-group-url">Button group</label>
<div role="group">
<span>https://</span>
<div class="input-group">
<input id="igc-group-url" />
<div align="inline-end">
<svg aria-hidden="true"><use href="#igc-info"></use></svg>
</div>
</div>
<span>.com</span>
</div>
</div>
</div>
</section>
</main>
</body>
</html>
Textarea And Block Addons
Block-start and block-end addons, textarea states, a code editor, character
counters, and the autosizing custom control remain native form controls.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Input Group Textarea 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="comment=''; commentCount=0; code=''; codeColumn=1; customText=''; customCount=0; textareaStatus='Ready'"
data-example="input-group-textarea-workflows"
>
<svg class="example-icon-definitions" aria-hidden="true">
<defs>
<symbol id="igt-copy" viewBox="0 0 24 24">
<rect width="14" height="14" x="8" y="8" rx="2"></rect>
<path
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
></path>
</symbol>
<symbol id="igt-refresh" viewBox="0 0 24 24">
<path d="M20 11a8 8 0 1 0 2 5M20 4v7h-7"></path>
</symbol>
<symbol id="igt-code-icon" viewBox="0 0 24 24">
<path d="m16 18 6-6-6-6M8 6l-6 6 6 6M14.5 4l-5 16"></path>
</symbol>
<symbol id="igt-send" viewBox="0 0 24 24">
<path d="m22 2-7 20-4-9-9-4ZM22 2 11 13"></path>
</symbol>
<symbol id="igt-info" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 16v-4M12 8h.01"></path>
</symbol>
</defs>
</svg>
<main
class="input-group-textarea-grid"
aria-label="Input group textarea examples"
>
<section
class="input-group-workflow"
data-example="input-group-block-start"
aria-labelledby="igt-start-title"
>
<h2 id="igt-start-title">Block start</h2>
<div class="field">
<label for="igt-start-input">Input</label>
<div class="input-group">
<input id="igt-start-input" placeholder="Enter your name" />
<div align="block-start">
<span>Full name</span>
</div>
</div>
<p>Header positioned above the input.</p>
</div>
<div class="field">
<label for="igt-start-textarea">Textarea</label>
<div class="input-group">
<textarea
id="igt-start-textarea"
placeholder="console.log('Hello, world!');"
></textarea>
<div align="block-start" border="true">
<svg aria-hidden="true"><use href="#igt-code-icon"></use></svg>
<span class="input-group-mono">script.js</span>
<button
size="icon-xs"
class="input-group-push-end"
variant="ghost"
type="button"
aria-label="Copy code"
ng-click="textareaStatus='Copied code'"
>
<svg aria-hidden="true"><use href="#igt-copy"></use></svg>
</button>
</div>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-block-end"
aria-labelledby="igt-end-title"
>
<h2 id="igt-end-title">Block end</h2>
<div class="field">
<label for="igt-amount">Input</label>
<div class="input-group">
<input
id="igt-amount"
inputmode="decimal"
placeholder="Enter amount"
/>
<div align="block-end">
<span>USD</span>
</div>
</div>
<p>Footer positioned below the input.</p>
</div>
<div class="field">
<label for="igt-comment">Textarea</label>
<div class="input-group">
<textarea
id="igt-comment"
ng-model="comment"
data-change="commentCount=comment.length"
maxlength="280"
placeholder="Write a comment..."
></textarea>
<div align="block-end">
<span>{{ commentCount }}/280</span>
<button
size="sm"
class="input-group-push-end"
type="button"
ng-click="textareaStatus='Posted comment'"
>
Post
</button>
</div>
</div>
<p>Footer positioned below the textarea.</p>
</div>
</section>
<section
class="input-group-workflow input-group-workflow-wide"
data-example="input-group-textarea"
aria-labelledby="igt-editor-title"
>
<h2 id="igt-editor-title">Code editor</h2>
<div class="input-group-code-editor input-group">
<textarea
id="igt-code"
ng-model="code"
data-change="codeColumn=code.length+1"
placeholder="console.log('Hello, world!');"
aria-label="JavaScript code"
></textarea>
<div align="block-start" border="true">
<span class="input-group-mono"
><svg aria-hidden="true"><use href="#igt-code-icon"></use></svg
>script.js</span
>
<button
size="icon-xs"
class="input-group-push-end"
variant="ghost"
type="button"
aria-label="Refresh code"
ng-click="code=''; textareaStatus='Reset code'"
>
<svg aria-hidden="true"><use href="#igt-refresh"></use></svg>
</button>
<button
size="icon-xs"
variant="ghost"
type="button"
aria-label="Copy code"
ng-click="textareaStatus='Copied code'"
>
<svg aria-hidden="true"><use href="#igt-copy"></use></svg>
</button>
</div>
<div align="block-end" border="true">
<span>Line 1, Column {{ codeColumn }}</span>
<button
size="sm"
class="input-group-push-end"
type="button"
ng-click="textareaStatus='Ran code'"
>
Run
</button>
</div>
</div>
<output class="input-group-output">{{ textareaStatus }}</output>
</section>
<section
class="input-group-workflow input-group-workflow-wide"
data-example="input-group-textarea-examples"
aria-labelledby="igt-examples-title"
>
<h2 id="igt-examples-title">Textarea states and addons</h2>
<div class="input-group-pair-grid">
<div class="field">
<label for="igt-default-textarea">Default textarea</label>
<textarea
id="igt-default-textarea"
placeholder="Enter your text here..."
></textarea>
</div>
<div class="field">
<label for="igt-invalid-textarea">Invalid</label>
<div class="input-group">
<textarea
id="igt-invalid-textarea"
aria-invalid="true"
placeholder="Enter your text here..."
></textarea>
</div>
</div>
<div class="field">
<label for="igt-disabled-textarea">Disabled</label>
<div class="input-group">
<textarea
id="igt-disabled-textarea"
disabled
placeholder="Enter your text here..."
></textarea>
</div>
</div>
<div class="field">
<label for="igt-prompt">Addon (block start)</label>
<div class="input-group">
<textarea id="igt-prompt"></textarea>
<div align="block-start">
<span>Ask, search or chat...</span
><svg class="input-group-push-end" aria-hidden="true">
<use href="#igt-info"></use>
</svg>
</div>
</div>
</div>
<div class="field">
<label for="igt-send-comment">Addon (send)</label>
<div class="input-group">
<textarea
id="igt-send-comment"
ng-model="comment"
data-change="commentCount=comment.length"
placeholder="Enter your text here..."
></textarea>
<div align="block-end">
<span>{{ commentCount }}/280 characters</span
><button
size="icon-xs"
class="input-group-push-end input-group-round-button"
type="button"
aria-label="Send"
ng-click="textareaStatus='Sent message'"
>
<svg aria-hidden="true"><use href="#igt-send"></use></svg>
</button>
</div>
</div>
</div>
<div class="field">
<label for="igt-actions">Addon (buttons)</label>
<div class="input-group">
<textarea
id="igt-actions"
placeholder="Share your thoughts..."
></textarea>
<div align="block-end">
<button
size="sm"
class="input-group-push-end"
variant="ghost"
type="button"
ng-click="textareaStatus='Cancelled comment'"
>
Cancel</button
><button
size="sm"
type="button"
ng-click="textareaStatus='Posted comment'"
>
Post comment
</button>
</div>
</div>
</div>
</div>
</section>
<section
class="input-group-workflow"
data-example="input-group-custom"
aria-labelledby="igt-custom-title"
>
<h2 id="igt-custom-title">Autosizing custom control</h2>
<div class="input-group">
<textarea
class="input-group-autosize"
ng-model="customText"
data-change="customCount=customText.length"
placeholder="Autoresize textarea..."
aria-label="Autosize textarea"
></textarea>
<div align="block-end">
<span>{{ customCount }} characters</span
><button
size="sm"
class="input-group-push-end"
type="button"
ng-click="textareaStatus='Submitted custom text'"
>
Submit
</button>
</div>
</div>
</section>
</main>
</body>
</html>
Right To Left
Logical addon placement and AngularTS model updates work without RTL-specific
component markup.
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 Input Group 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="rtlQuery=''; rtlComment=''; rtlCount=0; rtlStatus='جاهز'"
data-example="input-group-rtl"
>
<main
class="input-group-rtl-workflow"
aria-label="مجموعات إدخال من اليمين إلى اليسار"
>
<div class="input-group">
<input ng-model="rtlQuery" placeholder="بحث..." aria-label="بحث" />
<div align="inline-start">
<svg viewBox="0 0 24 24" aria-hidden="true">
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</div>
<div align="inline-end">١٢ نتيجة</div>
</div>
<div class="input-group">
<input placeholder="جاري البحث..." aria-label="جاري البحث" />
<div align="inline-end">
<output size="sm" aria-label="تحميل" class="spinner"></output>
</div>
</div>
<div class="input-group">
<input placeholder="جاري حفظ التغييرات..." aria-label="جاري الحفظ" />
<div align="inline-end">
<span>جاري الحفظ...</span
><output size="sm" aria-label="تحميل" class="spinner"></output>
</div>
</div>
<div class="field">
<label for="input-group-rtl-comment">منطقة النص</label>
<div class="input-group">
<textarea
id="input-group-rtl-comment"
ng-model="rtlComment"
data-change="rtlCount=rtlComment.length"
maxlength="280"
placeholder="اكتب تعليقًا..."
></textarea>
<div align="block-end">
<span>{{ rtlCount }}/٢٨٠</span>
<button
size="sm"
class="input-group-push-end"
type="button"
ng-click="rtlStatus='تم النشر'"
>
نشر
</button>
</div>
</div>
<p>تذييل موضع أسفل منطقة النص.</p>
</div>
<output class="input-group-output">
{{ rtlStatus }} · {{ rtlQuery || 'لا يوجد بحث' }}
</output>
</main>
</body>
</html>
Addon States
Visible addons participate in the control description. AngularCSS preserves
external description IDs as AngularTS inserts or hides addon 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 Input Group State 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="query='AngularCSS'; showCurrency=false; priceHidden=false"
>
<main class="component-state-grid" aria-label="Input group state contracts">
<section
class="component-state-section"
aria-labelledby="described-group-title"
>
<h2 id="described-group-title">Described addons</h2>
<p id="external-help" class="component-state-help">
Enter an invoice total.
</p>
<div id="described-group" class="input-group">
<input
aria-label="Invoice total"
aria-describedby="external-help currency-code"
/>
<span id="currency-code">USD</span>
<span align="inline-end" aria-hidden="true"> .00 </span>
</div>
</section>
<section
class="component-state-section"
aria-labelledby="button-group-title"
>
<h2 id="button-group-title">Action button</h2>
<div id="button-group" class="input-group">
<input aria-label="Documentation search" ng-model="query" />
<button type="button" ng-click="query=''">Clear</button>
</div>
</section>
<section
class="component-state-section"
aria-labelledby="dynamic-group-title"
>
<h2 id="dynamic-group-title">Conditional addon</h2>
<div id="dynamic-group" class="input-group">
<input
ng-attr-aria-label="{{ showCurrency ? 'Budget in USD' : 'Budget' }}"
aria-describedby="budget-help"
/>
<span ng-if="showCurrency" id="dynamic-addon"> USD </span>
</div>
<p id="budget-help" class="component-state-help">Monthly budget</p>
<button
variant="outline"
type="button"
ng-click="showCurrency=true"
ng-disabled="showCurrency"
>
Add currency
</button>
</section>
<section
class="component-state-section"
aria-labelledby="hidden-group-title"
>
<h2 id="hidden-group-title">Hidden addon</h2>
<div id="hidden-group" class="input-group">
<input aria-label="Price" aria-describedby="price-help" />
<span id="addon-price" ng-attr-aria-hidden="{{ priceHidden }}">
USD
</span>
</div>
<p id="price-help" class="component-state-help">Price before tax</p>
<button
variant="outline"
type="button"
ng-click="priceHidden=!priceHidden"
>
Toggle currency description
</button>
</section>
</main>
</body>
</html>
Clicking a non-button addon focuses the grouped control. Interactive addon
content remains responsible for its own native or composed behavior.
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. Grouped native controls and addons.
Anatomy
Root styling selector
Semantic structure
Use one native input, textarea, select, combobox, or spinbutton inside .input-group. Addons may be placed at inline-start, inline-end, block-start, or block-end with align. Buttons, menus, tooltips, and popovers retain their own behavior.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Authored | Direct addon placement: inline-start, inline-end, block-start, or block-end. |
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
border | Authored | Use true on a direct block addon to draw its dividing border. |
size | Authored | Direct action size: sm, icon-xs, or icon-sm; omit for the compact addon action. |
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
Input Group is styling-only. Native controls own focus, values, validation, and submission. Use a native label addon when clicking addon text should focus the control; AngularTS owns dynamic text and actions.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Keep one clearly labeled native control in each group. Use aria-describedby for explanatory addon text, aria-hidden for decorative text, and a native label for when an addon should focus the control.
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.17 - input-otp
A native one-time-code input with a segmented visual treatment.
Use one native input. The browser owns editing, paste, autofill, and validation.
<label for="code">One-time code</label>
<input
id="code"
autocomplete="one-time-code"
inputmode="numeric"
pattern="[0-9]{6}"
maxlength="6"
ng-model="code"
/>
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 Input Otp</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="otp='123456'"
data-example="input-otp-demo"
>
<div class="stack-sm">
<label for="one-time-code">One-time code</label>
<input
id="one-time-code"
class="visual-example"
name="one-time-code"
inputmode="numeric"
autocomplete="one-time-code"
pattern="[0-9]{6}"
minlength="6"
maxlength="6"
size="6"
ng-model="otp"
required
/>
<output class="visually-hidden" aria-live="polite">
Code: {{ otp }}
</output>
</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. One native one-time-code input.
Anatomy
Root styling selector
input[autocomplete="one-time-code"]
Semantic structure
Use one native input with autocomplete="one-time-code". The standard autocomplete purpose identifies the segmented one-time-code presentation; input mode, length, and pattern remain native attributes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-invalid | Authored | Validation state exposed to assistive technology and CSS. |
group | Authored | Optional visual grouping size. Use 3 to separate a six-character code into two groups. |
maxlength | Authored | Maximum native text length. |
pattern | Authored | Native regular-expression validation constraint. |
size | Authored | Native visible-character count; AngularCSS supports four or six code cells. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|
--otp-cell-size | Width of one visual code cell; defaults to eight spacing units. |
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
Input OTP is one styling-only native input. The browser owns typing, editing, paste, password-manager autofill, autocomplete=one-time-code, input mode, length, pattern validation, and form submission; AngularTS ng-model owns application state. AngularCSS registers no input-otp directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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.18 - item
Flexible list item primitive
Items compose media, content, title, description, and actions.
<div variant="outline" class="item">
<section>
<h3>Item title</h3>
<p>Supporting description.</p>
</section>
</div>
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 Item</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>
<ul style="max-width: 32rem">
<li variant="outline" id="outline-item" class="item">
<figure variant="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.75"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</svg>
</figure>
<section>
<h3>Profile verified</h3>
<p>Your public display name and email have been confirmed.</p>
</section>
<menu>
<button variant="outline" size="sm">Review</button>
</menu>
</li>
<li variant="muted" size="sm" id="compact-item" class="item">
<section>
<h3>Scheduled reports</h3>
<p>Weekly snapshots are ready for your team.</p>
</section>
<menu>
<span variant="secondary" class="badge">New</span>
</menu>
</li>
<li aria-disabled="true" id="disabled-item" class="item">
<section>
<h3>Archived workspace</h3>
<p>This workspace is retained for audit history.</p>
</section>
<menu>
<button variant="outline" size="sm" disabled>Restore</button>
</menu>
</li>
</ul>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Item 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="itemState={message:'Ready'}">
<main class="item-workflow-grid" aria-label="Item workflows">
<section data-example="item-demo" class="item-workflow">
<ul>
<li variant="outline" class="item">
<section>
<h3>Basic Item</h3>
<p>A simple item with title and description.</p>
</section>
<menu>
<button
variant="outline"
size="sm"
type="button"
ng-click="itemState.message='Basic action'"
>
Action
</button>
</menu>
</li>
<li variant="outline" size="sm" href="#verified" class="item">
<figure>
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M9 12.75 11.25 15 15 9.75"></path>
<circle cx="12" cy="12" r="9"></circle>
</svg>
</figure>
<section>
<h3>Your profile has been verified.</h3>
</section>
<menu aria-hidden="true">›</menu>
</li>
</ul>
</section>
<section data-example="item-avatar" class="item-workflow">
<ul>
<li variant="outline" class="item">
<figure>
<span class="item-avatar-large avatar"
><img src="../../images/avatars/01.png" alt="Evil Rabbit"
/></span>
</figure>
<section>
<h3>Evil Rabbit</h3>
<p>Last seen 5 months ago</p>
</section>
<menu>
<button
variant="outline"
size="icon-sm"
type="button"
aria-label="Invite Evil Rabbit"
>
+
</button>
</menu>
</li>
<li variant="outline" class="item">
<figure class="item-avatar-stack">
<span class="avatar"
><img
src="../../images/avatars/02.png"
alt="Jordan Lee" /></span
><span class="avatar"
><img src="../../images/avatars/03.png" alt="maxleiter" /></span
><span class="avatar"
><img src="../../images/avatars/01.png" alt="evilrabbit"
/></span>
</figure>
<section>
<h3>No Team Members</h3>
<p>Invite your team to collaborate on this project.</p>
</section>
<menu>
<button
variant="outline"
size="sm"
type="button"
ng-click="itemState.message='Invite opened'"
>
Invite
</button>
</menu>
</li>
</ul>
</section>
<section data-example="item-icon" class="item-workflow">
<article variant="outline" class="item">
<figure variant="icon">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path
d="M12 9v4m0 4h.01M10.3 3.7 2.5 17.2A2 2 0 0 0 4.2 20h15.6a2 2 0 0 0 1.7-2.8L13.7 3.7a2 2 0 0 0-3.4 0Z"
></path>
</svg>
</figure>
<section>
<h3>Security Alert</h3>
<p>New login detected from unknown device.</p>
</section>
<menu>
<button variant="outline" size="sm" type="button">Review</button>
</menu>
</article>
</section>
<section data-example="item-image" class="item-workflow">
<ul>
<li variant="outline" href="#midnight" class="item">
<figure variant="image">
<img
src="../../images/avatars/01.png"
alt="Midnight City Lights"
/>
</figure>
<section>
<h3>Midnight City Lights - Electric Nights</h3>
<p>Neon Dreams</p>
</section>
<section>
<p>3:45</p>
</section>
</li>
<li variant="outline" href="#coffee" class="item">
<figure variant="image">
<img
src="../../images/avatars/02.png"
alt="Coffee Shop Conversations"
/>
</figure>
<section>
<h3>Coffee Shop Conversations - Urban Stories</h3>
<p>The Morning Brew</p>
</section>
<section>
<p>4:05</p>
</section>
</li>
<li variant="outline" href="#digital" class="item">
<figure variant="image">
<img src="../../images/avatars/03.png" alt="Digital Rain" />
</figure>
<section>
<h3>Digital Rain - Binary Beats</h3>
<p>Cyber Symphony</p>
</section>
<section>
<p>3:30</p>
</section>
</li>
</ul>
</section>
<section
data-example="item-dropdown"
class="item-workflow item-dropdown-workflow"
>
<div ng-dropdown-menu>
<button variant="outline" type="button">
Select <span aria-hidden="true">⌄</span>
</button>
<menu>
<section>
<button ng-click="itemState.message='Selected Jordan Lee'">
<article size="xs" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/02.png" alt=""
/></span>
</figure>
<section>
<h3>Jordan Lee</h3>
<p>jordan@example.com</p>
</section>
</article></button
><button ng-click="itemState.message='Selected maxleiter'">
<article size="xs" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/03.png" alt=""
/></span>
</figure>
<section>
<h3>maxleiter</h3>
<p>maxleiter@vercel.com</p>
</section>
</article></button
><button ng-click="itemState.message='Selected evilrabbit'">
<article size="xs" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/01.png" alt=""
/></span>
</figure>
<section>
<h3>evilrabbit</h3>
<p>evilrabbit@vercel.com</p>
</section>
</article>
</button>
</section>
</menu>
</div>
</section>
<section data-example="item-group" class="item-workflow">
<ul>
<li variant="outline" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/02.png" alt="Jordan Lee"
/></span>
</figure>
<section>
<h3>Jordan Lee</h3>
<p>jordan@example.com</p>
</section>
<menu>
<button
variant="ghost"
size="icon-sm"
type="button"
aria-label="Invite Jordan Lee"
>
+
</button>
</menu>
</li>
<li variant="outline" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/03.png" alt="maxleiter"
/></span>
</figure>
<section>
<h3>maxleiter</h3>
<p>maxleiter@vercel.com</p>
</section>
<menu>
<button
variant="ghost"
size="icon-sm"
type="button"
aria-label="Invite maxleiter"
>
+
</button>
</menu>
</li>
<li variant="outline" class="item">
<figure>
<span class="avatar"
><img src="../../images/avatars/01.png" alt="evilrabbit"
/></span>
</figure>
<section>
<h3>evilrabbit</h3>
<p>evilrabbit@vercel.com</p>
</section>
<menu>
<button
variant="ghost"
size="icon-sm"
type="button"
aria-label="Invite evilrabbit"
>
+
</button>
</menu>
</li>
</ul>
</section>
<section
data-example="item-header"
class="item-workflow item-workflow-wide"
>
<ul class="item-header-grid">
<li variant="outline" class="item">
<header class="item-header">
<img src="../../images/avatars/01.png" alt="v0-1.5-sm" />
</header>
<section>
<h3>v0-1.5-sm</h3>
<p>Everyday tasks and UI generation.</p>
</section>
</li>
<li variant="outline" class="item">
<header class="item-header">
<img src="../../images/avatars/02.png" alt="v0-1.5-lg" />
</header>
<section>
<h3>v0-1.5-lg</h3>
<p>Advanced thinking or reasoning.</p>
</section>
</li>
<li variant="outline" class="item">
<header class="item-header">
<img src="../../images/avatars/03.png" alt="v0-2.0-mini" />
</header>
<section>
<h3>v0-2.0-mini</h3>
<p>Open Source model for everyone.</p>
</section>
</li>
</ul>
</section>
<section data-example="item-link" class="item-workflow">
<ul>
<li href="#documentation" class="item">
<section>
<h3>Visit our documentation</h3>
<p>Learn how to get started with our components.</p>
</section>
<menu aria-hidden="true">›</menu>
</li>
<li variant="outline" href="#external" class="item">
<section>
<h3>External resource</h3>
<p>Opens in a new tab with security attributes.</p>
</section>
<menu aria-hidden="true">↗</menu>
</li>
</ul>
</section>
<section data-example="item-size" class="item-workflow">
<ul>
<li variant="outline" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Default Size</h3>
<p>The standard size for most use cases.</p>
</section>
</li>
<li variant="outline" size="sm" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Small Size</h3>
<p>A compact size for dense layouts.</p>
</section>
</li>
<li variant="outline" size="xs" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Extra Small Size</h3>
<p>The most compact size available.</p>
</section>
</li>
</ul>
</section>
<section data-example="item-variant" class="item-workflow">
<ul>
<li class="item">
<figure variant="icon">□</figure>
<section>
<h3>Default Variant</h3>
<p>Transparent background with no border.</p>
</section>
</li>
<li variant="outline" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Outline Variant</h3>
<p>Outlined style with a visible border.</p>
</section>
</li>
<li variant="muted" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Muted Variant</h3>
<p>Muted background for secondary content.</p>
</section>
</li>
</ul>
</section>
<section data-example="muted-item-group" class="item-workflow">
<ul>
<li variant="muted" ng-repeat="number in [1,2,3]" class="item">
<section>
<h3>Item {{ number }}</h3>
<p>Item in muted group.</p>
</section>
<menu>
<button variant="outline" size="sm" type="button">Action</button>
</menu>
</li>
</ul>
</section>
<section data-example="outline-item-group" class="item-workflow">
<ul>
<li variant="outline" ng-repeat="number in [1,2,3]" class="item">
<figure variant="icon">□</figure>
<section>
<h3>Item {{ number }}</h3>
<p>Item with icon.</p>
</section>
</li>
</ul>
</section>
<section
data-example="file-upload-list"
class="item-workflow item-workflow-wide"
>
<ul>
<li
size="xs"
class="file-upload-item item"
ng-repeat="file in [{name:'document.pdf',progress:45,time:'2m 30s'},{name:'presentation.pptx',progress:78,time:'45s'},{name:'spreadsheet.xlsx',progress:12,time:'5m 12s'},{name:'image.jpg',progress:100,time:'Complete'}]"
>
<figure variant="icon">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"
></path>
<path d="M14 2v6h6"></path>
</svg>
</figure>
<section>
<h3>{{ file.name }}</h3>
</section>
<section class="file-upload-progress">
<progress
value="{{ file.progress }}"
max="100"
aria-label="Upload progress for {{ file.name }}"
></progress>
</section>
<menu class="file-upload-time">{{ file.time }}</menu>
</li>
</ul>
</section>
<section
data-example="item-rtl"
class="item-workflow"
dir="rtl"
lang="ar"
>
<ul>
<li variant="outline" class="item">
<section>
<h3>عنصر أساسي</h3>
<p>عنصر بسيط يحتوي على عنوان ووصف.</p>
</section>
<menu>
<button variant="outline" size="sm" type="button">إجراء</button>
</menu>
</li>
<li variant="outline" size="sm" href="#verified-rtl" class="item">
<figure>✓</figure>
<section>
<h3>تم التحقق من ملفك الشخصي.</h3>
</section>
<menu aria-hidden="true">‹</menu>
</li>
</ul>
</section>
<output class="item-workflow-output">{{ itemState.message }}</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. Semantic repeated-content composition.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
size | Authored | Item density: xs or sm; omit for the default size. |
variant | Authored | Item surface: outline or muted; direct figures additionally accept icon or image. |
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
Semantic repeated-content composition. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
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.
6.19 - pagination
Page navigation links
Use nav with aria-label="pagination" and mark the current page with
aria-current="page".
<nav aria-label="pagination" class="pagination">
<ul>
<li>
<a href="#">1</a>
</li>
<li>
<a aria-current="page" href="#">2</a>
</li>
</ul>
</nav>
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 Pagination</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="pagination-demo">
<main class="visual-example">
<nav aria-label="pagination" class="pagination">
<ul>
<li>
<a href="#previous" rel="prev" aria-label="Go to previous page">
<svg
icon="inline-start"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
<span>Previous</span>
</a>
</li>
<li>
<a href="#page-1">1</a>
</li>
<li>
<a href="#page-2" aria-current="page">2</a>
</li>
<li>
<a href="#page-3">3</a>
</li>
<li>
<span aria-hidden="true">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
<span>More pages</span>
</span>
</li>
<li>
<a href="#next" rel="next" aria-label="Go to next page">
<span>Next</span>
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</a>
</li>
</ul>
</nav>
</main>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Pagination 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="paginationWorkflow={showPage4:false,activePage:2,nextDisabled:false,rows:'25'}"
data-example="pagination-icons-only pagination-rtl pagination-simple"
>
<main class="visual-example">
<section aria-labelledby="pagination-dynamic-heading">
<header>
<h2 id="pagination-dynamic-heading">Application state</h2>
<div class="component-state-actions">
<button
type="button"
variant="outline"
size="sm"
ng-click="paginationWorkflow.showPage4=!paginationWorkflow.showPage4; paginationWorkflow.activePage=paginationWorkflow.showPage4 ? 4 : 2"
>
{{ paginationWorkflow.showPage4 ? 'Remove page 4' : 'Add page 4'
}}
</button>
<button
type="button"
variant="outline"
size="sm"
ng-click="paginationWorkflow.nextDisabled=!paginationWorkflow.nextDisabled"
>
{{ paginationWorkflow.nextDisabled ? 'Enable next' : 'Disable
next' }}
</button>
</div>
</header>
<nav
aria-label="Dynamic pagination"
id="dynamic-pagination"
class="pagination"
>
<ul>
<li>
<a
href="#page-1"
ng-click="paginationWorkflow.activePage=1"
aria-current="{{ paginationWorkflow.activePage === 1 ? 'page' : 'false' }}"
>1</a
>
</li>
<li>
<a
href="#page-2"
ng-click="paginationWorkflow.activePage=2"
aria-current="{{ paginationWorkflow.activePage === 2 ? 'page' : 'false' }}"
>2</a
>
</li>
<li>
<a
href="#page-3"
ng-click="paginationWorkflow.activePage=3"
aria-current="{{ paginationWorkflow.activePage === 3 ? 'page' : 'false' }}"
>3</a
>
</li>
<li ng-if="paginationWorkflow.showPage4">
<a
href="#page-4"
ng-click="paginationWorkflow.activePage=4"
aria-current="{{ paginationWorkflow.activePage === 4 ? 'page' : 'false' }}"
>4</a
>
</li>
<li>
<a
href="#next"
rel="next"
aria-label="Go to next page"
aria-disabled="{{ paginationWorkflow.nextDisabled }}"
>
<span>Next</span>
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</a>
</li>
</ul>
</nav>
</section>
<section aria-labelledby="pagination-simple-heading">
<header>
<h2 id="pagination-simple-heading">Simple</h2>
</header>
<nav aria-label="Simple pagination" class="pagination">
<ul>
<li>
<a href="#simple-1">1</a>
</li>
<li>
<a href="#simple-2" aria-current="page">2</a>
</li>
<li>
<a href="#simple-3">3</a>
</li>
<li>
<a href="#simple-4">4</a>
</li>
<li>
<a href="#simple-5">5</a>
</li>
</ul>
</nav>
</section>
<section aria-labelledby="pagination-icons-heading">
<header>
<h2 id="pagination-icons-heading">Rows</h2>
</header>
<div class="pagination-compact-row">
<label class="pagination-rows-field" for="pagination-rows-per-page">
<span>Rows per page</span>
<select
id="pagination-rows-per-page"
ng-model="paginationWorkflow.rows"
>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</label>
<nav aria-label="Compact pagination" class="pagination">
<ul>
<li>
<a
href="#compact-previous"
rel="prev"
aria-label="Go to previous page"
>
<svg
icon="inline-start"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</a>
</li>
<li>
<a href="#compact-next" rel="next" aria-label="Go to next page">
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</a>
</li>
</ul>
</nav>
</div>
<output class="workflow-output">
Rows: <span ng-bind="paginationWorkflow.rows"></span>
</output>
</section>
<section aria-labelledby="pagination-rtl-heading" lang="ar">
<header>
<h2 id="pagination-rtl-heading">الصفحات</h2>
</header>
<nav
dir="rtl"
aria-label="ترقيم الصفحات"
id="rtl-pagination"
class="pagination"
>
<ul>
<li>
<a
href="#rtl-previous"
rel="prev"
aria-label="الانتقال إلى الصفحة السابقة"
>
<svg
icon="inline-start"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
<span>السابق</span>
</a>
</li>
<li>
<a href="#rtl-1">١</a>
</li>
<li>
<a href="#rtl-2" aria-current="page">٢</a>
</li>
<li>
<a href="#rtl-3">٣</a>
</li>
<li>
<span>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="currentColor">
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
<span>صفحات إضافية</span>
</span>
</li>
<li>
<a
href="#rtl-next"
rel="next"
aria-label="الانتقال إلى الصفحة التالية"
>
<span>التالي</span>
<svg
icon="inline-end"
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</a>
</li>
</ul>
</nav>
</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 navigation, lists, and links.
Anatomy
Root styling selector
Semantic structure
Apply .pagination to a native nav containing a ul or ol with direct li children. The class distinguishes Pagination from other navigation landmarks; page, previous, and next controls remain native links. Ellipsis is optional. Compose rows-per-page controls beside Pagination with existing native form components; Pagination does not own that model.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-current | Authored | Current item or date state. |
aria-disabled | Authored | Semantic disabled state. |
dir | Authored | Text and interaction direction: ltr or rtl. |
rel | Authored | Use the prev or next link type for directional pagination controls. |
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
Native navigation, lists, list items, and links own pagination semantics and navigation. URLs, routing, page counts, rows-per-page values, and current-page application state remain AngularTS or application concerns. AngularCSS registers no pagination directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native nav landmark with an accessible label, a native list, and native links. Expose exactly one current destination with aria-current="page". Previous and next links need destination-specific accessible names; ellipsis is decorative and removed from the accessibility tree.
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.20 - popover
Floating rich content panels
Connect a native button to semantic popover content with popovertarget and
popover. The browser owns top-layer rendering, Escape, and light dismissal.
<span>
<button popovertarget="dimensions">Open</button>
<aside id="dimensions" popover>Content</aside>
</span>
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 Popover</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="popover-demo">
<main class="visual-example">
<span aria-label="Dimensions popover">
<button
type="button"
variant="outline"
popovertarget="popover-popover-1-content"
>
Open popover
</button>
<aside
aria-label="Dimensions"
id="popover-popover-1-content"
side="bottom"
align="center"
popover
>
<header>
<h2>Dimensions</h2>
<p>Set the dimensions for the layer.</p>
</header>
<form>
<label
><span>Width</span>
<input id="popover-width" value="100%" autofocus />
</label>
<label
><span>Max. width</span>
<input id="popover-max-width" value="300px" />
</label>
<label
><span>Height</span>
<input id="popover-height" value="25px" />
</label>
<label
><span>Max. height</span>
<input id="popover-max-height" value="none" />
</label>
</form>
</aside>
</span>
</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 Popover API disclosure.
Anatomy
Root styling selector
span:has(> [popovertarget] ~ [popover])
Semantic structure
Connect a native button’s popovertarget to one element with the matching id and popover. Header, title, and description selectors are optional styling hooks. Use native form controls inside the content; AngularTS owns their values and validation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Authored | Popover alignment: start, center, or end. |
popover | Authored | Native Popover API state and behavior on the surface. |
popovertarget | Authored | ID of the sibling popover controlled by the trigger. |
side | Authored | Preferred placement: top, right, bottom, or left. |
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
The native Popover API owns non-modal disclosure, top-layer rendering, outside pointer dismissal, and Escape closure. popovertarget connects the invoker to the popover element. AngularTS remains responsible for authored content, form values, and application state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native button invoker and give the popover content a useful accessible name when its context is not otherwise clear. Escape and pointer light-dismiss are browser behavior; add autofocus only when moving focus into the content is appropriate.
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.21 - skeleton
Loading placeholder primitive
Use class="skeleton" on a block element and control its size with normal CSS.
<div
style="height: 2.5rem; width: 2.5rem; border-radius: 9999px;"
class="skeleton"
></div>
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 Skeleton</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="skeleton-avatar skeleton-card skeleton-demo skeleton-form skeleton-rtl skeleton-table skeleton-text"
>
<main aria-label="Skeleton examples">
<section
class="skeleton-demo visual-example"
aria-label="Loading profile preview"
>
<output
id="labeled-skeleton"
aria-label="Loading avatar"
aria-hidden="false"
style="width: 3rem; height: 3rem; border-radius: 9999px"
class="skeleton"
></output>
<div class="skeleton-lines">
<div
id="decorative-skeleton"
aria-hidden="true"
style="width: 15.625rem; height: 1rem"
class="skeleton"
></div>
<div
aria-hidden="true"
style="width: 12.5rem; height: 1rem"
class="skeleton"
></div>
</div>
</section>
<section class="skeleton-card-demo" aria-label="Loading card">
<div class="skeleton-card-media skeleton"></div>
<div class="skeleton-line-wide skeleton"></div>
<div class="skeleton-line-medium skeleton"></div>
<div class="skeleton-button-placeholder skeleton"></div>
</section>
<section class="skeleton-form-demo" aria-label="Loading form">
<div>
<div class="skeleton-label-placeholder skeleton"></div>
<div class="skeleton-input-placeholder skeleton"></div>
</div>
<div>
<div class="skeleton-label-placeholder skeleton"></div>
<div class="skeleton-input-placeholder skeleton"></div>
</div>
<div class="skeleton-button-placeholder skeleton"></div>
</section>
<section class="skeleton-table-demo" aria-label="Loading table">
<div class="skeleton-table-heading skeleton"></div>
<div class="skeleton-table-row">
<div class="skeleton"></div>
<div class="skeleton"></div>
<div class="skeleton"></div>
</div>
<div class="skeleton-table-row">
<div class="skeleton"></div>
<div class="skeleton"></div>
<div class="skeleton"></div>
</div>
<div class="skeleton-table-row">
<div class="skeleton"></div>
<div class="skeleton"></div>
<div class="skeleton"></div>
</div>
</section>
<section class="skeleton-text-demo" aria-label="Loading text">
<div class="skeleton-line-wide skeleton"></div>
<div class="skeleton-line-wide skeleton"></div>
<div class="skeleton-line-medium skeleton"></div>
</section>
<section
class="skeleton-rtl-demo"
aria-label="تحميل الملف الشخصي"
dir="rtl"
lang="ar"
>
<div class="skeleton-avatar-placeholder skeleton"></div>
<div>
<div class="skeleton-line-wide skeleton"></div>
<div class="skeleton-line-medium skeleton"></div>
</div>
</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. Authored loading placeholder.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
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
Authored loading placeholder. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use the appropriate live-region or status semantics for dynamic feedback. Decorative feedback must stay hidden from assistive technology.
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.22 - spinner
Loading status indicator
Use class="spinner" on an SVG with an accessible label. Place it in an
output when status semantics are needed.
<svg aria-label="Loading" viewBox="0 0 24 24" class="spinner">
<circle cx="12" cy="12" r="10" />
</svg>
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 Spinner</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="spinner-demo">
<div class="visual-example">
<article variant="muted" class="item">
<figure>
<svg
viewBox="0 0 24 24"
fill="none"
aria-live="polite"
aria-label="Loading"
aria-busy="true"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</figure>
<section>
<h3>Processing payment...</h3>
</section>
<section class="spinner-amount">
<span>$100.00</span>
</section>
</article>
</div>
</body>
</html>
Composition workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Spinner 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="spinner-badge spinner-button spinner-custom spinner-empty spinner-input-group spinner-rtl spinner-size input-group-spinner"
>
<main class="spinner-workflows">
<div class="workflow-row" aria-label="Spinner sizes">
<svg
id="processing-spinner"
aria-live="assertive"
aria-label="Processing data"
style="width: 12px; height: 12px"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" class="spinner">
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<svg
aria-hidden="true"
style="width: 24px; height: 24px"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
<svg
aria-hidden="true"
style="width: 32px; height: 32px"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</div>
<div class="workflow-row" aria-label="Spinner badges">
<span class="badge"
><svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Syncing</span
>
<span variant="secondary" class="badge"
><svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Updating</span
>
<span variant="outline" class="badge"
><svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Processing</span
>
</div>
<div class="workflow-buttons-column" aria-label="Spinner buttons">
<button disabled size="sm">
<svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Loading...
</button>
<button variant="outline" disabled size="sm">
<svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Please wait
</button>
<button variant="secondary" disabled size="sm">
<svg
icon="inline-start"
viewBox="0 0 24 24"
fill="none"
class="spinner"
>
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/></svg
>Processing
</button>
</div>
<section class="spinner-empty-demo empty" aria-live="polite">
<header>
<figure variant="icon">
<svg viewBox="0 0 24 24" fill="none" class="spinner">
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</figure>
<h2>Processing your request</h2>
<p>
Please wait while we process your request. Do not refresh the page.
</p>
</header>
<section>
<button variant="outline" size="sm">Cancel</button>
</section>
</section>
<div class="workflow-input-groups" aria-label="Spinner input groups">
<div class="input-group">
<input placeholder="Searching..." />
<div align="inline-end">
<svg viewBox="0 0 24 24" fill="none" class="spinner">
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</div>
</div>
<div class="input-group">
<input placeholder="Saving changes..." />
<div align="inline-end">
<span>Saving...</span
><svg viewBox="0 0 24 24" fill="none" class="spinner">
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</div>
</div>
</div>
<article variant="muted" class="spinner-rtl-demo item" dir="rtl">
<figure>
<svg viewBox="0 0 24 24" fill="none" class="spinner">
<path
d="M21 12a9 9 0 1 1-6.22-8.56"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</figure>
<section>
<h3>جاري معالجة الدفع...</h3>
</section>
<section class="spinner-amount">
<span>١٠٠.٠٠ دولار</span>
</section>
</article>
</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. Authored status indicator.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
size | Authored | Spinner size: sm or lg; omit for the default size. |
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
Authored status indicator. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use the appropriate live-region or status semantics for dynamic feedback. Decorative feedback must stay hidden from assistive technology.
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.23 - stepper
Ordered multi-step workflow navigation
Present workflow progress as an ordered list inside navigation. The current step
is authored with aria-current="step"; routing and workflow state remain
application-owned.
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 Stepper</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="stepper-demo">
<nav class="visual-example" aria-label="Create customer">
<ol>
<li><a href="#account">Account</a></li>
<li><a href="#contacts" aria-current="step">Contacts</a></li>
<li><span>Permissions</span></li>
<li><span>Review</span></li>
</ol>
</nav>
</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 ordered workflow navigation.
Anatomy
Root styling selector
nav:has([aria-current="step"])
Semantic structure
Use a native nav containing one direct ordered list. Each item contains a link or text span, and aria-current=step on the current item identifies the Stepper without a class.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-current | Authored | Current item or date state. |
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
Stepper styles native ordered navigation and derives completed presentation from the authored current step. AngularTS or routing owns workflow progress and whether a destination is available.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use an ordered list inside a labeled navigation landmark. Apply aria-current=step to exactly one link or text label and do not make unavailable steps interactive.
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.24 - toggle
Pressed-state button primitive with aria-pressed state.
Use a native button with authored aria-pressed state. That state identifies
the control as a toggle and supplies its styling hook.
<button aria-pressed="true">Bold</button>
<button variant="outline" aria-pressed="false">Italic</button>
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 Toggle</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="bookmark=false;bold=false;italic=true"
data-example="toggle-demo toggle-outline toggle-sizes toggle-text"
>
<main class="visual-example">
<div class="row" aria-label="Bookmark toggle">
<button
variant="outline"
size="sm"
aria-label="Toggle bookmark"
aria-pressed="{{ bookmark }}"
ng-click="bookmark = !bookmark"
type="button"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M6 3h12v18l-6-4-6 4z" />
</svg>
Bookmark
</button>
</div>
<div class="row" aria-label="Text toggles">
<button
aria-label="Toggle italic text"
aria-pressed="{{ italic }}"
ng-click="italic = !italic"
type="button"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M10 4h7M7 20h7M14 4 10 20" />
</svg>
Italic
</button>
</div>
<div class="row" aria-label="Outline toggles">
<button
variant="outline"
aria-label="Toggle italic"
aria-pressed="{{ italic }}"
ng-click="italic = !italic"
type="button"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M10 4h7M7 20h7M14 4 10 20" />
</svg>
Italic
</button>
<button
variant="outline"
aria-label="Toggle bold"
aria-pressed="{{ bold }}"
ng-click="bold = !bold"
type="button"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M6 4h7a4 4 0 0 1 0 8H6zM6 12h8a4 4 0 0 1 0 8H6z" />
</svg>
Bold
</button>
</div>
<div class="row" aria-label="Toggle sizes">
<button variant="outline" size="sm" type="button" aria-pressed="false">
Small
</button>
<button variant="outline" type="button" aria-pressed="false">
Default
</button>
<button variant="outline" size="lg" type="button" aria-pressed="false">
Large
</button>
</div>
<output class="output">
Bookmark: {{ bookmark ? 'on' : 'off' }}, Bold: {{ bold ? 'on' : 'off'
}}, Italic: {{ italic ? 'on' : 'off' }}
</output>
</main>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Toggle 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="disabledState = true; rtlBookmark = false"
data-example="toggle-disabled toggle-rtl"
>
<main class="component-state-grid visual-example">
<section
class="component-state-section"
aria-labelledby="toggle-disabled-heading"
>
<h2 id="toggle-disabled-heading">Disabled</h2>
<div class="row">
<button
type="button"
ng-disabled="disabledState"
aria-pressed="false"
>
Disabled
</button>
<button
type="button"
variant="outline"
ng-disabled="disabledState"
aria-pressed="false"
>
Disabled
</button>
</div>
<button
type="button"
variant="outline"
size="sm"
ng-click="disabledState = !disabledState"
>
{{ disabledState ? 'Enable toggles' : 'Disable toggles' }}
</button>
</section>
<section
class="component-state-section"
aria-labelledby="toggle-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="toggle-rtl-heading">إشارة مرجعية</h2>
<button
type="button"
size="sm"
variant="outline"
aria-label="تبديل الإشارة المرجعية"
aria-pressed="{{ rtlBookmark }}"
ng-click="rtlBookmark = !rtlBookmark"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M6 3h12v18l-6-4-6 4z" />
</svg>
إشارة مرجعية
</button>
<output class="output">
الحالة: {{ rtlBookmark ? 'مفعلة' : 'غير مفعلة' }}
</output>
</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 button pressed state.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-disabled | Authored | Semantic disabled state. |
aria-pressed | Authored | Pressed state of a toggle control. |
size | Authored | Toggle size: sm or lg; omit for the default size. |
variant | Authored | Toggle presentation: outline; omit for the default style. |
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
Native button pressed state. AngularCSS supplies styling without a runtime directive. Native HTML owns platform behavior; AngularTS owns application values, commands, and authored state.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native button whenever the control performs an action. Keep an accessible name, preserve visible focus, and use disabled for unavailable native controls.
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.25 - toggle-group
Native radio or checkbox groups with a toggle-button presentation.
Use radios sharing a name for single selection, or checkboxes for independent
multiple selection.
<fieldset variant="outline" class="toggle-group">
<legend class="visually-hidden">Alignment</legend>
<label>
<input type="radio" name="alignment" value="left" ng-model="alignment" />
Left
</label>
<label>
<input type="radio" name="alignment" value="center" ng-model="alignment" />
Center
</label>
</fieldset>
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 Toggle Group</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="alignment='center'">
<div class="stack-sm">
<fieldset class="toggle-group visual-example" variant="outline">
<legend class="visually-hidden">Text alignment</legend>
<label>
<input
type="radio"
name="alignment"
value="left"
ng-model="alignment"
/>
Left
</label>
<label>
<input
type="radio"
name="alignment"
value="center"
ng-model="alignment"
/>
Center
</label>
<label>
<input
type="radio"
name="alignment"
value="right"
ng-model="alignment"
/>
Right
</label>
</fieldset>
<output class="output">
Alignment: <span ng-bind="alignment"></span>
</output>
</div>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Toggle Group 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="fontWeight='normal'; pageDirection='rtl'; bold=true; italic=true"
data-example="toggle-group-demo toggle-group-disabled toggle-group-font-weight-selector toggle-group-outline toggle-group-rtl toggle-group-sizes toggle-group-spacing toggle-group-vertical"
>
<main class="toggle-group-workflows visual-example">
<section aria-labelledby="toggle-format-heading">
<header><h2 id="toggle-format-heading">Formatting</h2></header>
<fieldset
class="toggle-group"
variant="outline"
id="multiple-toggle-group"
>
<legend class="visually-hidden">Text formatting</legend>
<label><input type="checkbox" ng-model="bold" />Bold</label>
<label><input type="checkbox" ng-model="italic" />Italic</label>
<label><input type="checkbox" />Underline</label>
</fieldset>
</section>
<section aria-labelledby="toggle-keyboard-heading">
<header>
<h2 id="toggle-keyboard-heading">Keyboard navigation</h2>
</header>
<fieldset
class="toggle-group"
variant="outline"
id="keyboard-toggle-group"
>
<legend class="visually-hidden">Text style</legend>
<label
><input type="radio" name="style" value="bold" checked />Bold</label
>
<label
><input
type="radio"
name="style"
value="italic"
disabled
/>Italic</label
>
<label
><input
type="radio"
name="style"
value="underline"
/>Underline</label
>
</fieldset>
</section>
<section aria-labelledby="toggle-disabled-heading">
<header><h2 id="toggle-disabled-heading">Disabled</h2></header>
<fieldset class="toggle-group" id="disabled-toggle-group" disabled>
<legend class="visually-hidden">Disabled formatting</legend>
<label><input type="checkbox" />Bold</label>
<label><input type="checkbox" />Italic</label>
<label><input type="checkbox" />Underline</label>
</fieldset>
</section>
<section aria-labelledby="toggle-weight-heading">
<header><h2 id="toggle-weight-heading">Font weight</h2></header>
<fieldset
class="toggle-group"
variant="outline"
spacing="2"
size="lg"
id="font-weight-toggle-group"
>
<legend class="visually-hidden">Font weight</legend>
<label class="toggle-weight-item"
><input
type="radio"
name="weight"
value="light"
ng-model="fontWeight"
/><strong style="font-weight: 300">Aa</strong
><span>Light</span></label
>
<label class="toggle-weight-item"
><input
type="radio"
name="weight"
value="normal"
ng-model="fontWeight"
/><strong style="font-weight: 400">Aa</strong
><span>Normal</span></label
>
<label class="toggle-weight-item"
><input
type="radio"
name="weight"
value="medium"
ng-model="fontWeight"
/><strong style="font-weight: 500">Aa</strong
><span>Medium</span></label
>
<label class="toggle-weight-item"
><input
type="radio"
name="weight"
value="bold"
ng-model="fontWeight"
/><strong style="font-weight: 700">Aa</strong
><span>Bold</span></label
>
</fieldset>
<output class="output">Selected: font-{{ fontWeight }}</output>
</section>
<section aria-labelledby="toggle-sizes-heading">
<header><h2 id="toggle-sizes-heading">Sizes and spacing</h2></header>
<div class="toggle-group-size-stack">
<fieldset class="toggle-group" size="sm" variant="outline">
<legend class="visually-hidden">Small position</legend>
<label
><input type="radio" name="small-position" checked />Top</label
>
<label><input type="radio" name="small-position" />Bottom</label>
</fieldset>
<fieldset
class="toggle-group"
variant="outline"
spacing="2"
id="spaced-toggle-group"
>
<legend class="visually-hidden">Spaced position</legend>
<label
><input type="radio" name="spaced-position" checked />Top</label
>
<label><input type="radio" name="spaced-position" />Bottom</label>
</fieldset>
</div>
</section>
<section aria-labelledby="toggle-vertical-heading">
<header><h2 id="toggle-vertical-heading">Vertical</h2></header>
<fieldset
class="toggle-group"
orientation="vertical"
spacing="1"
id="vertical-toggle-group"
>
<legend class="visually-hidden">Vertical formatting</legend>
<label><input type="checkbox" checked />Bold</label>
<label><input type="checkbox" checked />Italic</label>
<label><input type="checkbox" />Underline</label>
</fieldset>
</section>
<section
dir="{{ pageDirection }}"
lang="ar"
id="toggle-rtl-shell"
aria-labelledby="toggle-rtl-heading"
>
<header>
<h2 id="toggle-rtl-heading">اتجاه العرض</h2>
<button
type="button"
variant="outline"
size="sm"
ng-click="pageDirection = pageDirection === 'rtl' ? 'ltr' : 'rtl'"
>
Change direction
</button>
</header>
<fieldset class="toggle-group" variant="outline" id="rtl-toggle-group">
<legend class="visually-hidden">طريقة العرض</legend>
<label
><input type="radio" name="view" value="list" checked />قائمة</label
>
<label><input type="radio" name="view" value="grid" />شبكة</label>
<label><input type="radio" name="view" value="cards" />بطاقات</label>
</fieldset>
</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 radio or checkbox grouping.
Anatomy
Root styling selector
Semantic structure
Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
orientation | Authored | Group layout: vertical; omit for the horizontal layout. |
size | Authored | Control size: sm or lg; omit for the default size. |
spacing | Authored | Gap in spacing units: 1 or 2; omit to join controls. |
variant | Authored | Control presentation: outline; omit for the default style. |
Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.
CSS custom properties
| Variable | Purpose |
|---|
--toggle-group-gap | Gap between controls; defaults to 0. |
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
Toggle Group is a styling-only native fieldset: use radios sharing a name for single selection and checkboxes for multiple selection. The browser owns selection, arrow-key radio navigation, disabled state, focus, validation, and form submission; AngularTS ng-model owns application state. AngularCSS registers no toggle-group directive.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native button whenever the control performs an action. Keep an accessible name, preserve visible focus, and use disabled for unavailable native controls.
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.26 - validation-summary
Linked form validation messages
Place a validation summary before the related fields when submission reveals
several errors. Each message links directly to its native form control.
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 Validation Summary</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="validation-summary-demo">
<main class="visual-example">
<aside role="alert" tabindex="-1">
<header>
<h2>There are two problems with this form</h2>
<p>Correct the fields below, then submit again.</p>
</header>
<ul>
<li><a href="#customer-name">Enter a customer name.</a></li>
<li><a href="#customer-email">Enter a valid email address.</a></li>
</ul>
</aside>
<form>
<label for="customer-name">Customer name</label>
<input id="customer-name" required />
<label for="customer-email">Email</label>
<input id="customer-email" type="email" required />
</form>
</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. Authored validation messages linked to form controls.
Anatomy
Root styling selector
aside[role="alert"]:has(> header + ul)
Semantic structure
Use role="alert" on a semantic aside containing a direct header followed by a list of links to invalid controls. No classes or part markers are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
role | Authored | Explicit semantic role when native HTML does not provide one. |
tabindex | Authored | Keyboard focus order for composite descendants. |
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
Validation Summary presents authored error links. Native form validation, AngularTS form controllers, server responses, message visibility, and focus policy remain application-owned.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the summary a heading and link every message to its corresponding control. Use an alert or live region when errors appear after submission, then apply application focus policy deliberately.
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 - Components
Focused AngularCSS runtime components for coordinated interaction.
Components are the small runtime layer used only when native HTML cannot
coordinate the interaction. Every component includes a locally bundled,
non-scrollable iframe demo and its complete TypeScript-derived contract.
Each reference page answers:
- What the component does and where to use it.
- What semantic HTML and directive selectors it requires.
- Which parts, attributes, state hooks, CSS variables, and events it exposes.
- Which behavior belongs to AngularCSS, AngularTS, native HTML, or application
code.
- What accessibility and customization constraints apply.
7.1 - calendar
Calendar date grid structure
Use data-calendar-generated with data-month="YYYY-MM" to render a complete
month, including outside days. Previous and next controls update the visible
month, while selecting a date updates data-value and emits
angularcss:calendar-select. Bind that event with AngularTS ng-on-* so
application state remains responsible for the selected value.
<section
ng-calendar
data-calendar-generated
data-month="2026-05"
data-value="{{ selectedDate }}"
ng-on-angularcss:calendar-select="selectedDate = $event.detail.value"
>
<header>
<button type="button">Previous</button>
<h2></h2>
<button type="button">Next</button>
</header>
<div></div>
</section>
Use data-week-start="0" through "6" to choose the first weekday and
data-show-outside-days="false" to hide outside dates. Set
--calendar-cell-size in CSS to resize cells. Day cells support
arrow keys, Home, End, Page Up, and Page Down. Month changes emit
angularcss:calendar-month-change.
Omit data-calendar-generated to author every weekday and day cell yourself.
This mode supports selected, today, outside-month, disabled, booked, range, and
week-number attributes without replacing application markup.
Date pickers are compositions rather than a second model implementation: use a
native date or text input with ng-model, a field and label, a popover,
and this calendar grid. Use native input[type="time"] for time values and
ordinary buttons for presets. Booked dates use disabled plus
data-booked="true"; custom day content can be nested inside a date button, and
generated week numbers use native data elements.
The generated calendar is a Gregorian local-date UI backed by date-fns.
Non-Gregorian engines, natural-language parsing, and IANA time-zone conversion
are explicit application adapters: they provide localized labels and stable
YYYY-MM-DD values to the calendar, or bind native inputs and zone selectors
with AngularTS ng-model. AngularCSS does not silently convert calendar systems
or instants because those conversions require application locale and time-zone
policy.
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 Calendar</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-05-14'"
data-example="calendar-demo"
>
<div class="stack-sm">
<section
ng-calendar
data-calendar-generated
data-month="2026-05"
data-value="{{ selectedDate }}"
data-caption-layout="dropdown"
data-start-year="2024"
data-end-year="2028"
ng-on-angularcss:calendar-select="selectedDate = $event.detail.value"
class="calendar-demo visual-example"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
<output class="output" aria-live="polite">
Selected: {{ selectedDate }}
</output>
</div>
</body>
</html>
Selection And Options
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Calendar 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="calendar={basic:'',booked:'2026-09-08',caption:'2026-09-12',multiple:'2026-09-10,2026-09-12',rangeStart:'2026-09-10',rangeEnd:'2026-09-15',week:'2026-09-12'}"
data-example="calendar-basic calendar-booked-dates calendar-caption calendar-multiple calendar-range calendar-week-numbers"
>
<main
class="calendar-workflow-grid"
aria-label="Calendar selection workflows"
>
<section
class="calendar-workflow"
aria-labelledby="calendar-basic-heading"
>
<h2 id="calendar-basic-heading">Basic</h2>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ calendar.basic }}"
ng-on-angularcss:calendar-select="calendar.basic=$event.detail.value"
class="calendar-demo"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous basic month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next basic month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
<output class="calendar-workflow-output" aria-live="polite">
Selected: {{ calendar.basic || 'None' }}
</output>
</section>
<section
class="calendar-workflow"
aria-labelledby="calendar-booked-heading"
>
<h2 id="calendar-booked-heading">Booked dates</h2>
<article class="calendar-card card">
<section class="calendar-card-content">
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ calendar.booked }}"
data-booked-dates="2026-09-10,2026-09-11,2026-09-12,2026-09-13,2026-09-14,2026-09-15,2026-09-16,2026-09-17,2026-09-18,2026-09-19,2026-09-20,2026-09-21,2026-09-22,2026-09-23,2026-09-24"
ng-on-angularcss:calendar-select="calendar.booked=$event.detail.value"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous availability month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next availability month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
</section>
</article>
<output class="calendar-workflow-output" aria-live="polite">
Available date: {{ calendar.booked }}
</output>
</section>
<section
class="calendar-workflow"
aria-labelledby="calendar-caption-heading"
>
<h2 id="calendar-caption-heading">Dropdown caption</h2>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ calendar.caption }}"
data-caption-layout="dropdown"
data-start-year="2024"
data-end-year="2028"
ng-on-angularcss:calendar-select="calendar.caption=$event.detail.value"
class="calendar-demo"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous caption month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next caption month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
<output class="calendar-workflow-output" aria-live="polite">
Selected: {{ calendar.caption }}
</output>
</section>
<section
class="calendar-workflow"
aria-labelledby="calendar-multiple-heading"
>
<h2 id="calendar-multiple-heading">Multiple dates</h2>
<article class="calendar-card card">
<section class="calendar-card-content">
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-selection-mode="multiple"
data-values="{{ calendar.multiple }}"
ng-on-angularcss:calendar-select="calendar.multiple=$event.detail.values"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous multiple month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next multiple month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
</section>
</article>
<output class="calendar-workflow-output" aria-live="polite">
Selected dates: {{ calendar.multiple || 'None' }}
</output>
</section>
<section
class="calendar-workflow calendar-workflow-wide"
aria-labelledby="calendar-range-heading"
>
<h2 id="calendar-range-heading">Date range</h2>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-number-of-months="2"
data-selection-mode="range"
data-range-start-value="{{ calendar.rangeStart }}"
data-range-end-value="{{ calendar.rangeEnd }}"
ng-on-angularcss:calendar-select="calendar.rangeStart=$event.detail.range.start; calendar.rangeEnd=$event.detail.range.end"
class="calendar-demo"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous range month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next range month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
<output class="calendar-workflow-output" aria-live="polite">
Range: {{ calendar.rangeStart || 'None' }} to {{ calendar.rangeEnd ||
'None' }}
</output>
</section>
<section
class="calendar-workflow"
aria-labelledby="calendar-week-heading"
>
<h2 id="calendar-week-heading">Week numbers</h2>
<article class="calendar-card card">
<section class="calendar-card-content">
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ calendar.week }}"
data-show-week-numbers="true"
ng-on-angularcss:calendar-select="calendar.week=$event.detail.value"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous week-number month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next week-number month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
</section>
</article>
<output class="calendar-workflow-output" aria-live="polite">
Selected: {{ calendar.week }}
</output>
</section>
</main>
</body>
</html>
Reference Compositions
Custom day content remains authored HTML, while presets and time values use
ordinary buttons and native inputs bound by AngularTS. The Persian example is an
explicit application-provided calendar-system adapter: it supplies localized
labels and stable Gregorian interchange values without adding a second calendar
engine to AngularCSS.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Calendar Compositions</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="custom={start:'2026-09-10',end:'2026-09-15'}; presetDate='2026-09-12'; time={date:'2026-09-12',start:'09:00',end:'17:00'}; rtlDate='2026-09-12'; hijriDate='2025-06-12'; customDays=[{v:'2026-08-30',d:'30',p:'',o:true},{v:'2026-08-31',d:'31',p:'',o:true},{v:'2026-09-01',d:'1',p:'$100',o:false},{v:'2026-09-02',d:'2',p:'$100',o:false},{v:'2026-09-03',d:'3',p:'$100',o:false},{v:'2026-09-04',d:'4',p:'$100',o:false},{v:'2026-09-05',d:'5',p:'$120',o:false},{v:'2026-09-06',d:'6',p:'$120',o:false},{v:'2026-09-07',d:'7',p:'$100',o:false},{v:'2026-09-08',d:'8',p:'$100',o:false},{v:'2026-09-09',d:'9',p:'$100',o:false},{v:'2026-09-10',d:'10',p:'$100',o:false},{v:'2026-09-11',d:'11',p:'$100',o:false},{v:'2026-09-12',d:'12',p:'$120',o:false},{v:'2026-09-13',d:'13',p:'$120',o:false},{v:'2026-09-14',d:'14',p:'$100',o:false},{v:'2026-09-15',d:'15',p:'$100',o:false},{v:'2026-09-16',d:'16',p:'$100',o:false},{v:'2026-09-17',d:'17',p:'$100',o:false},{v:'2026-09-18',d:'18',p:'$100',o:false},{v:'2026-09-19',d:'19',p:'$120',o:false},{v:'2026-09-20',d:'20',p:'$120',o:false},{v:'2026-09-21',d:'21',p:'$100',o:false},{v:'2026-09-22',d:'22',p:'$100',o:false},{v:'2026-09-23',d:'23',p:'$100',o:false},{v:'2026-09-24',d:'24',p:'$100',o:false},{v:'2026-09-25',d:'25',p:'$100',o:false},{v:'2026-09-26',d:'26',p:'$120',o:false},{v:'2026-09-27',d:'27',p:'$120',o:false},{v:'2026-09-28',d:'28',p:'$100',o:false},{v:'2026-09-29',d:'29',p:'$100',o:false},{v:'2026-09-30',d:'30',p:'$100',o:false},{v:'2026-10-01',d:'1',p:'',o:true},{v:'2026-10-02',d:'2',p:'',o:true},{v:'2026-10-03',d:'3',p:'',o:true},{v:'2026-10-04',d:'4',p:'',o:true},{v:'2026-10-05',d:'5',p:'',o:true},{v:'2026-10-06',d:'6',p:'',o:true},{v:'2026-10-07',d:'7',p:'',o:true},{v:'2026-10-08',d:'8',p:'',o:true},{v:'2026-10-09',d:'9',p:'',o:true},{v:'2026-10-10',d:'10',p:'',o:true}]; hijriDays=[{v:'2025-05-17',d:'۲۷',o:true},{v:'2025-05-18',d:'۲۸',o:true},{v:'2025-05-19',d:'۲۹',o:true},{v:'2025-05-20',d:'۳۰',o:true},{v:'2025-05-21',d:'۳۱',o:true},{v:'2025-05-22',d:'۱',o:false},{v:'2025-05-23',d:'۲',o:false},{v:'2025-05-24',d:'۳',o:false},{v:'2025-05-25',d:'۴',o:false},{v:'2025-05-26',d:'۵',o:false},{v:'2025-05-27',d:'۶',o:false},{v:'2025-05-28',d:'۷',o:false},{v:'2025-05-29',d:'۸',o:false},{v:'2025-05-30',d:'۹',o:false},{v:'2025-05-31',d:'۱۰',o:false},{v:'2025-06-01',d:'۱۱',o:false},{v:'2025-06-02',d:'۱۲',o:false},{v:'2025-06-03',d:'۱۳',o:false},{v:'2025-06-04',d:'۱۴',o:false},{v:'2025-06-05',d:'۱۵',o:false},{v:'2025-06-06',d:'۱۶',o:false},{v:'2025-06-07',d:'۱۷',o:false},{v:'2025-06-08',d:'۱۸',o:false},{v:'2025-06-09',d:'۱۹',o:false},{v:'2025-06-10',d:'۲۰',o:false},{v:'2025-06-11',d:'۲۱',o:false},{v:'2025-06-12',d:'۲۲',o:false},{v:'2025-06-13',d:'۲۳',o:false},{v:'2025-06-14',d:'۲۴',o:false},{v:'2025-06-15',d:'۲۵',o:false},{v:'2025-06-16',d:'۲۶',o:false},{v:'2025-06-17',d:'۲۷',o:false},{v:'2025-06-18',d:'۲۸',o:false},{v:'2025-06-19',d:'۲۹',o:false},{v:'2025-06-20',d:'۳۰',o:false},{v:'2025-06-21',d:'۳۱',o:false},{v:'2025-06-22',d:'۱',o:true},{v:'2025-06-23',d:'۲',o:true},{v:'2025-06-24',d:'۳',o:true},{v:'2025-06-25',d:'۴',o:true},{v:'2025-06-26',d:'۵',o:true},{v:'2025-06-27',d:'۶',o:true}]"
data-example="calendar-custom-days calendar-presets calendar-rtl calendar-time calendar-hijri"
>
<main class="calendar-composition-grid" aria-label="Calendar compositions">
<section
class="calendar-composition calendar-composition-wide"
aria-labelledby="custom-days-heading"
>
<h2 id="custom-days-heading">Custom day prices</h2>
<article class="calendar-card card">
<section class="calendar-card-content">
<section
ng-calendar
data-selection-mode="range"
data-range-start-value="{{ custom.start }}"
data-range-end-value="{{ custom.end }}"
ng-on-angularcss:calendar-select="custom.start=$event.detail.range.start; custom.end=$event.detail.range.end"
class="calendar-custom-days"
>
<header>
<h3>September 2026</h3>
</header>
<div>
<abbr>Su</abbr><abbr>Mo</abbr><abbr>Tu</abbr><abbr>We</abbr
><abbr>Th</abbr><abbr>Fr</abbr><abbr>Sa</abbr>
<button
type="button"
ng-repeat="day in customDays"
value="{{ day.v }}"
data-outside="{{ day.o }}"
aria-label="{{ day.v }} {{ day.p }}"
>
<strong>{{ day.d }}</strong><span>{{ day.p }}</span>
</button>
</div>
</section>
</section>
</article>
<output class="calendar-workflow-output" aria-live="polite">
Range: {{ custom.start }} to {{ custom.end }}
</output>
</section>
<section class="calendar-composition" aria-labelledby="preset-heading">
<h2 id="preset-heading">Presets</h2>
<article size="sm" class="calendar-preset-card card">
<section class="calendar-preset-content">
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ presetDate }}"
ng-on-angularcss:calendar-select="presetDate=$event.detail.value"
class="calendar-flush calendar-preset-grid"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous preset month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next preset month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
</section>
<footer class="calendar-preset-footer">
<button
type="button"
variant="outline"
size="sm"
ng-click="presetDate='2026-09-12'"
>
Today
</button>
<button
type="button"
variant="outline"
size="sm"
ng-click="presetDate='2026-09-13'"
>
Tomorrow
</button>
<button
type="button"
variant="outline"
size="sm"
ng-click="presetDate='2026-09-15'"
>
In 3 days
</button>
<button
type="button"
variant="outline"
size="sm"
ng-click="presetDate='2026-09-19'"
>
In a week
</button>
<button
type="button"
variant="outline"
size="sm"
ng-click="presetDate='2026-09-26'"
>
In 2 weeks
</button>
</footer>
</article>
<output class="calendar-workflow-output" aria-live="polite">
Selected: {{ presetDate }}
</output>
</section>
<section class="calendar-composition" aria-labelledby="time-heading">
<h2 id="time-heading">Date and time</h2>
<article size="sm" class="calendar-time-card card">
<section class="calendar-time-content">
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ time.date }}"
ng-on-angularcss:calendar-select="time.date=$event.detail.value"
class="calendar-flush"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous time month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next time month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
</section>
<footer class="calendar-time-footer">
<label
><span>Start</span>
<div class="input-group">
<input
type="time"
ng-model="time.start"
aria-label="Start time"
/><span
><svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 2" /></svg
></span></div
></label>
<label
><span>End</span>
<div class="input-group">
<input
type="time"
ng-model="time.end"
aria-label="End time"
/><span
><svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 2" /></svg
></span></div
></label>
</footer>
</article>
<output class="calendar-workflow-output" aria-live="polite">
{{ time.date }} · {{ time.start }}–{{ time.end }}
</output>
</section>
<section
class="calendar-composition"
aria-labelledby="rtl-heading"
dir="rtl"
lang="ar-SA"
>
<h2 id="rtl-heading">تقويم من اليمين إلى اليسار</h2>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-value="{{ rtlDate }}"
data-caption-layout="dropdown"
data-start-year="2024"
data-end-year="2028"
ng-on-angularcss:calendar-select="rtlDate=$event.detail.value"
class="calendar-demo calendar-rtl-grid"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="الشهر السابق"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="الشهر التالي"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</header>
<div></div>
</section>
<output class="calendar-workflow-output" aria-live="polite">
التاريخ: {{ rtlDate }}
</output>
</section>
<section
class="calendar-composition"
aria-labelledby="hijri-heading"
dir="rtl"
lang="fa"
>
<h2 id="hijri-heading">تقویم هجری شمسی</h2>
<section
ng-calendar
data-value="{{ hijriDate }}"
ng-on-angularcss:calendar-select="hijriDate=$event.detail.value"
class="calendar-demo calendar-hijri-grid"
aria-label="خرداد ۱۴۰۴"
>
<header>
<h3>خرداد ۱۴۰۴</h3>
</header>
<div>
<abbr>ش</abbr><abbr>ی</abbr><abbr>د</abbr><abbr>س</abbr
><abbr>چ</abbr><abbr>پ</abbr><abbr>ج</abbr>
<button
type="button"
ng-repeat="day in hijriDays"
value="{{ day.v }}"
data-outside="{{ day.o }}"
aria-label="روز {{ day.d }}"
>
{{ day.d }}
</button>
</div>
</section>
<output class="calendar-workflow-output" aria-live="polite">
روز انتخابشده: {{ hijriDate }}
</output>
</section>
</main>
</body>
</html>
Date Picker Compositions
Date Picker is a composition of Field, Input Group, Popover, Calendar, Button,
and native time input primitives. The artifact below implements all eight
checked-in reference workflows: basic, standalone demo, date of birth, parsed
text input, natural-language input, range, RTL, and date with time.
The page loads a locally bundled TypeScript application adapter. AngularTS owns
the values and commands, while chrono-node parses natural-language input into
the Calendar’s stable YYYY-MM-DD interchange value. No CDN or source
TypeScript module is loaded by the 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 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>
<script src="../../js/date-picker-demo.umd.js"></script>
</head>
<body
ng-app="datePickerDemo"
ng-controller="DatePickerDemoController as picker"
ng-cloak
data-example="date-picker-basic date-picker-demo date-picker-dob date-picker-input date-picker-natural-language date-picker-range date-picker-rtl date-picker-time"
>
<main class="date-picker-grid" aria-label="Date picker workflows">
<section class="date-picker-workflow">
<h2>Basic</h2>
<div class="date-picker-field-compact field">
<label for="date-picker-basic">Date</label>
<span id="date-picker-basic-popover">
<button
id="date-picker-basic"
type="button"
variant="outline"
class="date-picker-trigger"
popovertarget="popover-date-picker-workflows-1-content"
>
{{ picker.basicDate ? picker.format(picker.basicDate) : 'Pick a
date' }}
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a basic date"
id="popover-date-picker-workflows-1-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
ng-attr-data-value="{{ picker.basicDate }}"
ng-on-angularcss:calendar-select="picker.selectBasic($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous basic month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next basic month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
</section>
<section class="date-picker-workflow">
<h2>Demo</h2>
<span id="date-picker-demo-popover">
<button
type="button"
variant="outline"
class="date-picker-trigger date-picker-trigger-between"
ng-attr-empty="{{ picker.demoDate ? undefined : '' }}"
popovertarget="popover-date-picker-workflows-2-content"
>
<span
>{{ picker.demoDate ? picker.format(picker.demoDate) : 'Pick a
date' }}</span
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a demo date"
id="popover-date-picker-workflows-2-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
ng-attr-data-value="{{ picker.demoDate }}"
ng-on-angularcss:calendar-select="picker.selectDemo($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous demo month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next demo month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</section>
<section class="date-picker-workflow">
<h2>Date of birth</h2>
<div class="date-picker-field-compact field">
<label for="date-picker-dob">Date of birth</label>
<span id="date-picker-dob-popover">
<button
id="date-picker-dob"
type="button"
variant="outline"
class="date-picker-trigger"
popovertarget="popover-date-picker-workflows-3-content"
>
{{ picker.dobDate ? picker.format(picker.dobDate) : 'Select date'
}}
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a birth date"
id="popover-date-picker-workflows-3-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
ng-attr-data-month="{{ picker.month(picker.dobDate) }}"
ng-attr-data-value="{{ picker.dobDate }}"
data-caption-layout="dropdown"
data-start-year="1900"
data-end-year="2026"
ng-on-angularcss:calendar-select="picker.selectDob($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous birth month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next birth month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
</section>
<section class="date-picker-workflow">
<h2>Input</h2>
<div class="date-picker-input-field field">
<label for="date-picker-input">Subscription Date</label>
<div class="input-group">
<input
id="date-picker-input"
ng-model="picker.inputValue"
data-change="picker.updateInput()"
ng-keydown="picker.openPopover('date-picker-input-popover', $event)"
placeholder="June 01, 2025"
/>
<div align="inline-end">
<span id="date-picker-input-popover">
<button
type="button"
variant="ghost"
size="icon-xs"
aria-label="Select subscription date"
popovertarget="popover-date-picker-workflows-4-content"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="5" width="18" height="16" rx="2"></rect>
<path d="M16 3v4M8 3v4M3 10h18"></path>
</svg>
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a subscription date"
id="popover-date-picker-workflows-4-content"
side="bottom"
align="end"
popover
>
<section
ng-calendar
data-calendar-generated
ng-attr-data-month="{{ picker.month(picker.inputDate) }}"
ng-attr-data-value="{{ picker.inputDate }}"
ng-on-angularcss:calendar-select="picker.selectInput($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous subscription month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next subscription month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
</div>
</div>
</section>
<section class="date-picker-workflow date-picker-workflow-wide">
<h2>Natural language</h2>
<div class="date-picker-natural-field field">
<label for="date-picker-natural">Schedule Date</label>
<div class="input-group">
<input
id="date-picker-natural"
ng-model="picker.naturalValue"
data-change="picker.updateNatural()"
ng-keydown="picker.openPopover('date-picker-natural-popover', $event)"
placeholder="Tomorrow or next week"
/>
<div align="inline-end">
<span id="date-picker-natural-popover">
<button
type="button"
variant="ghost"
size="icon-xs"
aria-label="Select schedule date"
popovertarget="popover-date-picker-workflows-5-content"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="5" width="18" height="16" rx="2"></rect>
<path d="M16 3v4M8 3v4M3 10h18"></path>
</svg>
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a schedule date"
id="popover-date-picker-workflows-5-content"
side="bottom"
align="end"
popover
>
<section
ng-calendar
data-calendar-generated
ng-attr-data-month="{{ picker.month(picker.naturalDate) }}"
ng-attr-data-value="{{ picker.naturalDate }}"
data-caption-layout="dropdown"
data-start-year="2024"
data-end-year="2028"
ng-on-angularcss:calendar-select="picker.selectNatural($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous schedule month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next schedule month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
</div>
<output class="calendar-workflow-output">
Your post will be published on
<strong>{{ picker.format(picker.naturalDate) }}</strong>.
</output>
</div>
</section>
<section class="date-picker-workflow date-picker-workflow-wide">
<h2>Range</h2>
<div class="date-picker-range-field field">
<label for="date-picker-range">Date Picker Range</label>
<span id="date-picker-range-popover">
<button
id="date-picker-range"
type="button"
variant="outline"
class="date-picker-trigger"
popovertarget="popover-date-picker-workflows-6-content"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="5" width="18" height="16" rx="2"></rect>
<path d="M16 3v4M8 3v4M3 10h18"></path>
</svg>
<span
>{{ picker.formatShort(picker.rangeStart) }} - {{
picker.formatShort(picker.rangeEnd) }}</span
>
</button>
<aside
class="calendar-popover-content"
aria-label="Choose a date range"
id="popover-date-picker-workflows-6-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
ng-attr-data-month="{{ picker.month(picker.rangeStart) }}"
data-number-of-months="2"
data-selection-mode="range"
ng-attr-data-range-start-value="{{ picker.rangeStart }}"
ng-attr-data-range-end-value="{{ picker.rangeEnd }}"
ng-on-angularcss:calendar-select="picker.selectRange($event.detail.range)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous range month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next range month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
</section>
<section class="date-picker-workflow" dir="rtl" lang="ar">
<h2>من اليمين إلى اليسار</h2>
<span id="date-picker-rtl-popover">
<button
type="button"
variant="outline"
class="date-picker-trigger date-picker-trigger-between"
ng-attr-empty="{{ picker.rtlDate ? undefined : '' }}"
popovertarget="popover-date-picker-workflows-7-content"
>
<span
>{{ picker.rtlDate ? picker.formatRtl(picker.rtlDate) : 'اختر
تاريخًا' }}</span
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</button>
<aside
class="calendar-popover-content"
aria-label="اختر تاريخًا"
id="popover-date-picker-workflows-7-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
ng-attr-data-value="{{ picker.rtlDate }}"
ng-on-angularcss:calendar-select="picker.selectRtl($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="الشهر السابق"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="الشهر التالي"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</section>
<section class="date-picker-workflow date-picker-workflow-wide">
<h2>Date and time</h2>
<div class="date-picker-time-fields">
<div class="field">
<label for="date-picker-time-date">Date</label>
<span id="date-picker-time-popover">
<button
id="date-picker-time-date"
type="button"
variant="outline"
class="date-picker-trigger date-picker-trigger-between"
popovertarget="popover-date-picker-workflows-8-content"
>
<span
>{{ picker.timeDate ? picker.formatShort(picker.timeDate) :
'Select date' }}</span
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</button>
<aside
class="calendar-popover-content"
aria-label="Choose an appointment date"
id="popover-date-picker-workflows-8-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
ng-attr-data-month="{{ picker.month(picker.timeDate) }}"
ng-attr-data-value="{{ picker.timeDate }}"
data-caption-layout="dropdown"
data-start-year="2024"
data-end-year="2028"
ng-on-angularcss:calendar-select="picker.selectTimeDate($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous appointment month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next appointment month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
</aside>
</span>
</div>
<div class="field">
<label for="date-picker-time-value">Time</label>
<input
id="date-picker-time-value"
type="time"
step="1"
ng-model="picker.time"
/>
</div>
</div>
</section>
</main>
</body>
</html>
Date Picker With Dropdowns
This focused composition keeps the Popover open after selecting a date so the
user can change the month or year and confirm with Done. Selection and the Done
command are implemented in the locally bundled TypeScript adapter.
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 With Dropdowns</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>
<script src="../../js/date-picker-demo.umd.js"></script>
</head>
<body
ng-app="datePickerDemo"
ng-controller="DatePickerDemoController as picker"
ng-cloak
data-example="data-picker-with-dropdowns"
>
<main class="date-picker-dropdown-demo visual-example">
<div class="date-picker-dropdown-field field">
<label for="date-picker-with-dropdowns">Date</label>
<span id="date-picker-dropdown-popover">
<button
id="date-picker-with-dropdowns"
type="button"
variant="outline"
class="date-picker-trigger date-picker-trigger-between"
popovertarget="popover-date-picker-with-dropdowns-1-content"
>
<span
>{{ picker.dropdownDate ? picker.format(picker.dropdownDate) :
'Pick a date' }}</span
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</button>
<aside
class="calendar-popover-content date-picker-dropdown-content"
aria-label="Choose a date with dropdowns"
id="popover-date-picker-with-dropdowns-1-content"
side="bottom"
align="start"
popover
>
<section
ng-calendar
data-calendar-generated
data-month="2026-09"
data-caption-layout="dropdown"
data-start-year="2020"
data-end-year="2030"
ng-attr-data-value="{{ picker.dropdownDate }}"
ng-on-angularcss:calendar-select="picker.selectDropdown($event.detail.value)"
>
<header>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Previous dropdown month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6"></path>
</svg>
</button>
<h3></h3>
<button
type="button"
size="icon"
variant="ghost"
aria-label="Next dropdown month"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</button>
</header>
<div></div>
</section>
<footer class="date-picker-dropdown-footer">
<button
type="button"
variant="outline"
size="sm"
ng-click="picker.finishDropdown()"
>
Done
</button>
</footer>
</aside>
</span>
</div>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-calendar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Use native elements for authored structure. Component classes are optional visual hooks when an HTML relationship is not specific enough.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-current | Input/output | Current item or date state. |
aria-disabled | Output | Semantic disabled state. |
aria-label | Input/output | Accessible name when visible text is insufficient. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
aria-live | Output | Announcement priority for updates to a live region. |
aria-pressed | Input/output | Pressed state of a toggle control. |
data-booked | Output | Whether a generated calendar day is booked. |
data-booked-dates | Input | Comma-separated ISO dates styled as booked. |
data-calendar-generated | Input | Enables generated month markup inside the authored Calendar shell. |
data-calendar-preset | Input | Generated calendar preset: single, multiple, or range. |
data-caption-layout | Input | Caption controls: label or dropdown. |
data-columns | Input | Number of columns used for calendar grid keyboard movement; defaults to 7. |
data-disabled-after | Input | Last selectable date as an ISO date. |
data-disabled-before | Input | First selectable date as an ISO date. |
data-disabled-dates | Input | Comma-separated ISO dates that cannot be selected. |
data-end-year | Input | Final year offered by a dropdown caption. |
data-min-nights | Input | Minimum number of nights accepted by range selection. |
data-month | Input/output | Displayed month in YYYY-MM form. |
data-months | Output | Number of month grids currently rendered. |
data-number-of-months | Input | Number of consecutive months to render. |
data-outside | Input/output | Whether a day belongs to an adjacent month. |
data-range-end | Output | Marks the final day in the selected range. |
data-range-end-value | Input/output | Selected range end as an ISO date. |
data-range-invalid | Output | Whether the pending range violates the minimum-night constraint. |
data-range-middle | Output | Marks a day between the selected range boundaries. |
data-range-start | Output | Marks the first day in the selected range. |
data-range-start-value | Input/output | Selected range start as an ISO date. |
data-selection-mode | Input | Selection behavior: single, multiple, or range. |
data-show-outside-days | Input | Shows dates from adjacent months when true. |
data-show-week-numbers | Input/output | Shows ISO-style week numbers when true. |
data-start-year | Input | First year offered by a dropdown caption. |
data-value | Input/output | Selected ISO date for single selection. |
data-values | Input/output | Comma-separated selected ISO dates for multiple selection. |
data-week-start | Input | First weekday as an integer from 0 (Sunday) to 6 (Saturday). |
dir | Input | Text and interaction direction: ltr or rtl. |
lang | Input | Language used for generated labels and localized text. |
selected | Output | Selected value reflected by the component. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
value | Output | Native value or authored component value. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--calendar-cell-size | Width and height of calendar controls and day cells. |
DOM events
angularcss:calendar-month-changeangularcss:calendar-range-invalidangularcss:calendar-select
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
The directive owns generated Gregorian month grids, local-date navigation, selectable day state, range and multiple-selection signaling, disabled and booked constraints, caption controls, week numbers, keyboard grid movement, and synchronized authored attributes. AngularTS remains responsible for application models, parsed text, commands, validation, and composed popover state. Natural-language and non-Gregorian conversion remain explicit application adapters; the packaged Date Picker demo uses locally bundled chrono-node without adding a second model implementation.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the calendar or its visible title a useful accessible name. Generated weekdays are column headers; week numbers are row headers; day buttons expose selected, current, disabled, outside, booked, and range state. Arrow keys, Home, End, Page Up, and Page Down move through the date grid, while RTL reverses horizontal movement. Date Picker triggers must keep an accessible name and preserve focus through the composed 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 [ng-calendar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.2 - carousel
Accessible drag and snap carousel powered by Embla
Use a required content viewport and track around authored slide items. The
TypeScript directive initializes the locally bundled Embla engine, synchronizes
controls and accessible state, and supports pointer dragging and keyboard
navigation.
<section
ng-carousel
align="start"
style="--carousel-item-size: 50%; --carousel-gap: 0.5rem"
>
<div>
<ul>
<li>Slide</li>
</ul>
</div>
</section>
Use orientation="vertical" for vertical movement and dir="rtl" for RTL.
--carousel-item-size controls single or multi-item layouts and
--carousel-gap controls spacing. Add autoplay and optionally
autoplay-delay="2000" for the same locally bundled plugin behavior as the
checked-in reference. The root mirrors snap index, snap count, item count, and
boundary state.
angularcss:carousel-ready and angularcss:carousel-change expose the Embla
API, zero-based snap index, snap count, selected item index, selected item, and
total item count. Bind those events with AngularTS when the application needs a
counter; AngularCSS does not create or replace an AngularTS 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 Carousel</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="carousel-demo">
<main class="visual-example">
<section ng-carousel class="carousel-demo" aria-label="Numbered slides">
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</main>
</body>
</html>
Behavior workflows
The following functional page covers API state, multiple visible items, vertical
orientation, and autoplay.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Carousel 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="apiState={index:0,count:5}; autoplayState={index:0,count:5}"
data-example="carousel-api carousel-multiple carousel-orientation carousel-plugin"
>
<main
class="carousel-workflow-grid"
aria-label="Carousel behavior workflows"
>
<section class="carousel-workflow" aria-labelledby="carousel-api-heading">
<h2 id="carousel-api-heading">API</h2>
<section
ng-carousel
class="carousel-api-demo"
aria-label="API numbered slides"
ng-on-angularcss:carousel-ready="apiState=$event.detail"
ng-on-angularcss:carousel-change="apiState=$event.detail"
>
<div>
<ul>
<li>
<article class="card">
<section class="carousel-square">
<span>1</span>
</section>
</article>
</li>
<li>
<article class="card">
<section class="carousel-square">
<span>2</span>
</section>
</article>
</li>
<li>
<article class="card">
<section class="carousel-square">
<span>3</span>
</section>
</article>
</li>
<li>
<article class="card">
<section class="carousel-square">
<span>4</span>
</section>
</article>
</li>
<li>
<article class="card">
<section class="carousel-square">
<span>5</span>
</section>
</article>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous API slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next API slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
<output class="carousel-status" aria-live="polite">
Slide {{ apiState.index + 1 }} of {{ apiState.count }}
</output>
</section>
<section
class="carousel-workflow"
aria-labelledby="carousel-multiple-heading"
>
<h2 id="carousel-multiple-heading">Multiple items</h2>
<section
ng-carousel
align="start"
class="carousel-multiple-demo"
aria-label="Multiple numbered slides"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous group"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next group"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</section>
<section
class="carousel-workflow"
aria-labelledby="carousel-orientation-heading"
>
<h2 id="carousel-orientation-heading">Vertical orientation</h2>
<section
ng-carousel
orientation="vertical"
align="start"
class="carousel-vertical-demo"
aria-label="Vertical numbered slides"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-vertical-card">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-vertical-card">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-vertical-card">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-vertical-card">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-vertical-card">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous vertical slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next vertical slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</section>
<section
class="carousel-workflow"
aria-labelledby="carousel-plugin-heading"
>
<h2 id="carousel-plugin-heading">Autoplay plugin</h2>
<section
ng-carousel
autoplay
autoplay-delay="2000"
class="carousel-api-demo"
aria-label="Autoplay numbered slides"
ng-on-angularcss:carousel-ready="autoplayState=$event.detail"
ng-on-angularcss:carousel-change="autoplayState=$event.detail"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous autoplay slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next autoplay slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
<output class="carousel-status" aria-live="polite">
Autoplay slide {{ autoplayState.index + 1 }} of {{ autoplayState.count
}}
</output>
</section>
</main>
</body>
</html>
Layout workflows
RTL direction, responsive item sizing, and custom spacing remain semantic HTML
and authored CSS 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 Carousel Compositions</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="carousel-rtl carousel-size carousel-spacing"
>
<main
class="carousel-composition-grid"
aria-label="Carousel layout compositions"
>
<section
class="carousel-workflow"
aria-labelledby="carousel-rtl-heading"
dir="rtl"
lang="ar"
>
<h2 id="carousel-rtl-heading">من اليمين إلى اليسار</h2>
<section
ng-carousel
dir="rtl"
class="carousel-demo"
aria-label="شرائح مرقمة"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>١</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>٢</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>٣</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>٤</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square">
<span>٥</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="الشريحة السابقة"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="الشريحة التالية"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</section>
<section
class="carousel-workflow"
aria-labelledby="carousel-size-heading"
>
<h2 id="carousel-size-heading">Responsive size</h2>
<section
ng-carousel
align="start"
class="carousel-size-demo"
aria-label="Sized numbered slides"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-medium">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous sized slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next sized slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</section>
<section
class="carousel-workflow carousel-composition-wide"
aria-labelledby="carousel-spacing-heading"
>
<h2 id="carousel-spacing-heading">Custom spacing</h2>
<section
ng-carousel
align="start"
class="carousel-spacing-demo"
aria-label="Tightly spaced numbered slides"
>
<div>
<ul>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-small">
<span>1</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-small">
<span>2</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-small">
<span>3</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-small">
<span>4</span>
</section>
</article>
</div>
</li>
<li>
<div class="carousel-item-padding">
<article class="card">
<section class="carousel-square carousel-square-small">
<span>5</span>
</section>
</article>
</div>
</li>
</ul>
</div>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Previous tightly spaced slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m15 18-6-6 6-6" />
</svg>
</button>
<button
size="icon-sm"
variant="outline"
type="button"
aria-label="Next tightly spaced slide"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6" />
</svg>
</button>
</section>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-carousel]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
The content viewport and its direct track child are required. Items must be direct track children. Navigation controls and dots are optional.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Input | Cross-axis alignment: start, center, or end. |
aria-current | Output | Current item or date state. |
aria-disabled | Output | Semantic disabled state. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-label | Input/output | Accessible name when visible text is insufficient. |
aria-roledescription | Output | Human-readable description of the component role. |
autoplay | Input | Enables the locally bundled Embla autoplay plugin. |
autoplay-delay | Input | Autoplay delay in milliseconds. |
contain-scroll | Input | Embla scroll containment mode. |
dir | Input | Text and interaction direction: ltr or rtl. |
drag-free | Input | Allows free dragging between snap points. |
draggable | Input | Set to false to disable pointer dragging. |
loop | Input | Allows navigation to wrap from the final item to the first. |
orientation | Input/output | Layout direction: horizontal or vertical. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
skip-snaps | Input | Allows momentum to skip snap points. |
slides-to-scroll | Input | Number of slides advanced as one snap group. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--carousel-gap | Gap between slides; defaults to four spacing units. |
--carousel-item-size | Slide basis; defaults to 100%. |
DOM events
angularcss:carousel-changeangularcss:carousel-ready
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
The directive uses Embla to own drag gestures, snap selection, orientation, loop boundaries, control availability, and optional autoplay. AngularTS remains responsible for counters, business actions, and other application state consumed from the carousel DOM events.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
The root is an accessible carousel region, every authored item is exposed as a labeled slide, and unavailable previous or next controls are disabled. Give the region a useful accessible name and keep authored slide content 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 [ng-carousel], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.3 - combobox
Search input with selectable options
Compose a searchable listbox with one ng-combobox root and semantic child
elements identified by combobox part classes. AngularTS ng-model, filters, and
event expressions remain the source of truth for query and selected-value state.
AngularCSS supplies popup disclosure, active-descendant navigation, disabled
handling, collision placement, and visual state.
<div
ng-combobox
ng-on-angularcss:combobox-select="selected=$event.detail.value; query=selected"
>
<header>
<input
aria-label="Framework"
ng-model="query"
placeholder="Select a framework"
/>
<button type="button" aria-label="Show frameworks" value="toggle"></button>
</header>
<aside aria-label="Framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:query"
data-value="{{ framework }}"
ng-attr-aria-selected="{{ selected === framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
Add auto-highlight when opening or filtering should highlight the first
enabled result. Without it, the popup opens without an active option until the
user presses an arrow key. Bind angularcss:combobox-open-change when the root
uses controlled open="{{ state.open }}" state.
For multiple selection, add multiple, render chips from AngularTS state, and
bind each option’s aria-selected value. Selection events include
multiple: true; angularcss:combobox-remove-last only signals Backspace on an
empty chip input. AngularCSS never replaces the application’s collection.
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 Combobox</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="frameworks=['Next.js','SvelteKit','Nuxt.js','Remix','Astro']; basic={query:'',selected:''}; automatic={query:'',selected:''}"
data-example="combobox-auto-highlight combobox-basic combobox-demo"
>
<main class="visual-example">
<div
id="basic-combobox"
ng-combobox
ng-on-angularcss:combobox-select="basic.selected=$event.detail.value; basic.query=$event.detail.value"
>
<header>
<input
aria-label="Framework"
ng-model="basic.query"
placeholder="Select a framework"
/>
<button
type="button"
aria-label="Show frameworks"
value="toggle"
></button>
</header>
<aside aria-label="Framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:basic.query"
ng-attr-aria-selected="{{ basic.selected === framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
<div
id="auto-combobox"
ng-combobox
auto-highlight
ng-on-angularcss:combobox-select="automatic.selected=$event.detail.value; automatic.query=$event.detail.value"
>
<header>
<input
aria-label="Auto-highlight framework"
ng-model="automatic.query"
placeholder="Select a framework"
/>
<button
type="button"
aria-label="Show auto-highlight frameworks"
value="toggle"
></button>
</header>
<aside aria-label="Auto-highlight framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:automatic.query"
ng-attr-aria-selected="{{ automatic.selected === framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
<output class="visually-hidden" aria-live="polite">
Basic: <span ng-bind="basic.selected || 'none'"></span>. Automatic:
<span ng-bind="automatic.selected || 'none'"></span>.
</output>
</main>
</body>
</html>
Reference Workflows
Clear, disabled, grouped, input-addon, invalid, and separate popup-trigger
compositions are functional in this artifact. Put the selected-value label
inside the direct toggle button. When a composition needs a compact button
inside an input shell, use a direct native button.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Combobox 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="frameworks=['Next.js','SvelteKit','Nuxt.js','Remix','Astro']; clearState={query:'Next.js',selected:'Next.js'}; grouped={query:'',selected:''}; invalidState={query:'',selected:''}; inputGroupState={query:'',selected:''}; popup={query:'',selected:'Select country'}; timezoneGroups=[{value:'Americas',items:['(GMT-5) New York','(GMT-8) Los Angeles','(GMT-6) Chicago','(GMT-5) Toronto','(GMT-8) Vancouver','(GMT-3) São Paulo']},{value:'Europe',items:['(GMT+0) London','(GMT+1) Paris','(GMT+1) Berlin','(GMT+1) Rome','(GMT+1) Madrid','(GMT+1) Amsterdam']},{value:'Asia/Pacific',items:['(GMT+9) Tokyo','(GMT+8) Shanghai','(GMT+8) Singapore','(GMT+4) Dubai','(GMT+11) Sydney','(GMT+9) Seoul']}]; countries=['Argentina','Australia','Brazil','Canada','China','Colombia','Egypt','France','Germany','Italy','Japan','Kenya','Mexico','New Zealand','Nigeria','South Africa','South Korea','United Kingdom','United States']"
data-example="combobox-clear combobox-disabled combobox-groups combobox-input-group combobox-invalid combobox-popup"
>
<main class="combobox-workflows visual-example">
<section class="combobox-workflow">
<div
id="clear-combobox"
ng-combobox
ng-on-angularcss:combobox-select="clearState.selected=$event.detail.value; clearState.query=$event.detail.value"
ng-on-angularcss:combobox-clear="clearState.selected=''; clearState.query=''"
>
<header>
<input
aria-label="Clearable framework"
ng-model="clearState.query"
placeholder="Select a framework"
/>
<button type="button" value="clear"></button>
</header>
<aside aria-label="Clearable framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:clearState.query"
data-value="{{ framework }}"
ng-attr-aria-selected="{{ clearState.selected === framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
</section>
<section class="combobox-workflow">
<div id="disabled-combobox" ng-combobox>
<header>
<input
aria-label="Disabled framework"
placeholder="Select a framework"
disabled
/>
<button
type="button"
aria-label="Show disabled frameworks"
disabled
value="toggle"
></button>
</header>
<aside aria-label="Disabled framework options">
<div>
<ul>
<li
ng-repeat="framework in frameworks"
data-value="{{ framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
</section>
<section class="combobox-workflow">
<div
id="groups-combobox"
ng-combobox
ng-on-angularcss:combobox-select="grouped.selected=$event.detail.value; grouped.query=$event.detail.value"
>
<header>
<input
aria-label="Grouped timezone"
ng-model="grouped.query"
placeholder="Select a timezone"
/>
<button
type="button"
aria-label="Show grouped timezones"
value="toggle"
></button>
</header>
<aside aria-label="Grouped timezone options">
<p>No timezones found.</p>
<div>
<section
ng-repeat="group in timezoneGroups"
ng-if="(group.items | filter:grouped.query).length"
>
<h3>{{ group.value }}</h3>
<ul>
<li
ng-repeat="zone in group.items | filter:grouped.query"
data-value="{{ zone }}"
ng-attr-aria-selected="{{ grouped.selected === zone }}"
>
{{ zone }}
</li>
</ul>
<hr />
</section>
</div>
</aside>
</div>
</section>
<section class="combobox-workflow">
<div
id="input-group-combobox"
ng-combobox
ng-on-angularcss:combobox-select="inputGroupState.selected=$event.detail.value; inputGroupState.query=$event.detail.value"
>
<header>
<span class="combobox-globe" aria-hidden="true"></span>
<input
aria-label="Timezone with icon"
ng-model="inputGroupState.query"
placeholder="Select a timezone"
/>
<button
type="button"
aria-label="Show icon timezones"
value="toggle"
></button>
</header>
<aside
aria-label="Icon timezone options"
style="--combobox-options-width: 15rem"
>
<p>No timezones found.</p>
<div>
<section
ng-repeat="group in timezoneGroups"
ng-if="(group.items | filter:inputGroupState.query).length"
>
<h3>{{ group.value }}</h3>
<ul>
<li
ng-repeat="zone in group.items | filter:inputGroupState.query"
data-value="{{ zone }}"
>
{{ zone }}
</li>
</ul>
</section>
</div>
</aside>
</div>
</section>
<section class="combobox-workflow">
<div
id="invalid-combobox"
ng-combobox
ng-on-angularcss:combobox-select="invalidState.selected=$event.detail.value; invalidState.query=$event.detail.value"
>
<header>
<input
aria-label="Invalid framework"
aria-invalid="true"
ng-model="invalidState.query"
placeholder="Select a framework"
/>
<button
type="button"
aria-label="Show invalid frameworks"
value="toggle"
></button>
</header>
<aside aria-label="Invalid framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:invalidState.query"
data-value="{{ framework }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
</section>
<section class="combobox-workflow combobox-popup-workflow">
<div
id="popup-combobox"
ng-combobox
ng-on-angularcss:combobox-select="popup.selected=$event.detail.value; popup.query=''"
>
<button
type="button"
variant="outline"
aria-label="Country"
value="toggle"
>
<span ng-bind="popup.selected"></span>
</button>
<aside aria-label="Country options">
<header>
<input
aria-label="Search countries"
ng-model="popup.query"
placeholder="Search"
/>
</header>
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="country in countries | filter:popup.query"
data-value="{{ country }}"
ng-attr-aria-selected="{{ popup.selected === country }}"
>
{{ country }}
</li>
</ul>
</div>
</aside>
</div>
</section>
<output class="visually-hidden" aria-live="polite">
Clear: <span ng-bind="clearState.selected || 'none'"></span>. Grouped:
<span ng-bind="grouped.selected || 'none'"></span>. Popup:
<span ng-bind="popup.selected"></span>.
</output>
</main>
</body>
</html>
Custom, Multiple, And RTL
Custom option content and chip collections remain ordinary authored HTML and
AngularTS application state.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Combobox Compositions</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="frameworks=['Next.js','SvelteKit','Nuxt.js','Remix','Astro']; custom={query:'',selected:''}; multi={query:'',next:true,svelte:false,nuxt:false,remix:false,astro:false}; rtl={query:'',technology:true,design:false,business:false,marketing:false,education:false,health:false}; countries=[{code:'ar',label:'Argentina',continent:'South America'},{code:'au',label:'Australia',continent:'Oceania'},{code:'br',label:'Brazil',continent:'South America'},{code:'ca',label:'Canada',continent:'North America'},{code:'cn',label:'China',continent:'Asia'},{code:'co',label:'Colombia',continent:'South America'},{code:'eg',label:'Egypt',continent:'Africa'},{code:'fr',label:'France',continent:'Europe'},{code:'de',label:'Germany',continent:'Europe'},{code:'it',label:'Italy',continent:'Europe'},{code:'jp',label:'Japan',continent:'Asia'},{code:'ke',label:'Kenya',continent:'Africa'},{code:'mx',label:'Mexico',continent:'North America'},{code:'nz',label:'New Zealand',continent:'Oceania'},{code:'ng',label:'Nigeria',continent:'Africa'},{code:'za',label:'South Africa',continent:'Africa'},{code:'kr',label:'South Korea',continent:'Asia'},{code:'gb',label:'United Kingdom',continent:'Europe'},{code:'us',label:'United States',continent:'North America'}]; categories=['التكنولوجيا','التصميم','الأعمال','التسويق','التعليم','الصحة']"
data-example="combobox-custom combobox-multiple combobox-rtl"
>
<main class="combobox-compositions visual-example">
<section class="combobox-composition">
<div
id="custom-combobox"
ng-combobox
ng-on-angularcss:combobox-select="custom.selected=$event.detail.value; custom.query=$event.detail.value"
>
<header>
<input
aria-label="Country with details"
ng-model="custom.query"
placeholder="Search countries..."
/>
<button
type="button"
aria-label="Show detailed countries"
value="toggle"
></button>
</header>
<aside aria-label="Detailed country options">
<p>No countries found.</p>
<div>
<ul>
<li
ng-repeat="country in countries | filter:custom.query"
data-value="{{ country.label }}"
ng-attr-aria-selected="{{ custom.selected === country.label }}"
>
<article size="xs" class="combobox-custom-item item">
<section>
<h3>{{ country.label }}</h3>
<p>{{ country.continent }} ({{ country.code }})</p>
</section>
</article>
</li>
</ul>
</div>
</aside>
</div>
</section>
<section class="combobox-composition">
<div
id="multiple-combobox"
ng-combobox
multiple
auto-highlight
ng-on-angularcss:combobox-select="$event.detail.value === 'Next.js' ? multi.next=!multi.next : $event.detail.value === 'SvelteKit' ? multi.svelte=!multi.svelte : $event.detail.value === 'Nuxt.js' ? multi.nuxt=!multi.nuxt : $event.detail.value === 'Remix' ? multi.remix=!multi.remix : multi.astro=!multi.astro"
ng-on-angularcss:combobox-remove-last="multi.astro ? multi.astro=false : multi.remix ? multi.remix=false : multi.nuxt ? multi.nuxt=false : multi.svelte ? multi.svelte=false : multi.next=false"
>
<fieldset>
<span ng-if="multi.next" animate>
Next.js
<button
type="button"
aria-label="Remove Next.js"
ng-click="multi.next=false"
value="remove"
></button>
</span>
<span ng-if="multi.svelte" animate>
SvelteKit
<button
type="button"
aria-label="Remove SvelteKit"
ng-click="multi.svelte=false"
value="remove"
></button>
</span>
<span ng-if="multi.nuxt" animate>
Nuxt.js
<button
type="button"
aria-label="Remove Nuxt.js"
ng-click="multi.nuxt=false"
value="remove"
></button>
</span>
<span ng-if="multi.remix" animate>
Remix
<button
type="button"
aria-label="Remove Remix"
ng-click="multi.remix=false"
value="remove"
></button>
</span>
<span ng-if="multi.astro" animate>
Astro
<button
type="button"
aria-label="Remove Astro"
ng-click="multi.astro=false"
value="remove"
></button>
</span>
<input
aria-label="Frameworks"
ng-model="multi.query"
placeholder="Add framework"
/>
</fieldset>
<aside aria-label="Multiple framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="framework in frameworks | filter:multi.query"
data-value="{{ framework }}"
ng-attr-aria-selected="{{ framework === 'Next.js' ? multi.next : framework === 'SvelteKit' ? multi.svelte : framework === 'Nuxt.js' ? multi.nuxt : framework === 'Remix' ? multi.remix : multi.astro }}"
>
{{ framework }}
</li>
</ul>
</div>
</aside>
</div>
</section>
<section
class="combobox-composition combobox-rtl-composition"
lang="ar"
dir="rtl"
>
<div class="field">
<label for="rtl-combobox-input">الفئات</label>
<div
id="rtl-combobox"
ng-combobox
multiple
auto-highlight
ng-on-angularcss:combobox-select="$event.detail.value === 'التكنولوجيا' ? rtl.technology=!rtl.technology : $event.detail.value === 'التصميم' ? rtl.design=!rtl.design : $event.detail.value === 'الأعمال' ? rtl.business=!rtl.business : $event.detail.value === 'التسويق' ? rtl.marketing=!rtl.marketing : $event.detail.value === 'التعليم' ? rtl.education=!rtl.education : rtl.health=!rtl.health"
ng-on-angularcss:combobox-remove-last="rtl.health ? rtl.health=false : rtl.education ? rtl.education=false : rtl.marketing ? rtl.marketing=false : rtl.business ? rtl.business=false : rtl.design ? rtl.design=false : rtl.technology=false"
>
<fieldset>
<span ng-if="rtl.technology" animate>
التكنولوجيا
<button
type="button"
aria-label="إزالة التكنولوجيا"
ng-click="rtl.technology=false"
value="remove"
></button>
</span>
<span ng-if="rtl.design" animate>
التصميم
<button
type="button"
aria-label="إزالة التصميم"
ng-click="rtl.design=false"
value="remove"
></button>
</span>
<span ng-if="rtl.business" animate>
الأعمال
<button
type="button"
aria-label="إزالة الأعمال"
ng-click="rtl.business=false"
value="remove"
></button>
</span>
<span ng-if="rtl.marketing" animate>
التسويق
<button
type="button"
aria-label="إزالة التسويق"
ng-click="rtl.marketing=false"
value="remove"
></button>
</span>
<span ng-if="rtl.education" animate>
التعليم
<button
type="button"
aria-label="إزالة التعليم"
ng-click="rtl.education=false"
value="remove"
></button>
</span>
<span ng-if="rtl.health" animate>
الصحة
<button
type="button"
aria-label="إزالة الصحة"
ng-click="rtl.health=false"
value="remove"
></button>
</span>
<input
id="rtl-combobox-input"
aria-label="الفئات"
ng-model="rtl.query"
placeholder="أضف فئات"
/>
</fieldset>
<aside lang="ar" aria-label="خيارات الفئات">
<p>لم يتم العثور على فئات.</p>
<div>
<ul>
<li
ng-repeat="category in categories | filter:rtl.query"
data-value="{{ category }}"
ng-attr-aria-selected="{{ category === 'التكنولوجيا' ? rtl.technology : category === 'التصميم' ? rtl.design : category === 'الأعمال' ? rtl.business : category === 'التسويق' ? rtl.marketing : category === 'التعليم' ? rtl.education : rtl.health }}"
>
{{ category }}
</li>
</ul>
</div>
</aside>
</div>
</div>
</section>
<output class="visually-hidden" aria-live="polite">
Country: <span ng-bind="custom.selected || 'none'"></span>. Frameworks:
<span ng-bind="multi.next ? 'Next.js' : 'none'"></span>. Categories:
<span ng-bind="rtl.technology ? 'التكنولوجيا' : 'none'"></span>.
</output>
</main>
</body>
</html>
Controlled State
The state artifact covers controlled disclosure, disabled-option skipping, Home
and End navigation, dynamic options, and outside dismissal.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Combobox State 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="state={query:'',selected:'Next.js',open:false,showAstro:false}; stateOptions=[{label:'Next.js',disabled:false},{label:'SvelteKit',disabled:true},{label:'Nuxt.js',disabled:false},{label:'Remix',disabled:false}]"
>
<main class="combobox-state-workflows visual-example">
<div class="combobox-state-controls">
<button
type="button"
variant="outline"
ng-click="state.open=!state.open"
>
Toggle popup
</button>
<button
type="button"
variant="outline"
ng-click="state.showAstro=!state.showAstro"
>
Toggle Astro option
</button>
</div>
<div
id="state-combobox"
ng-combobox
auto-highlight
open="{{ state.open }}"
ng-on-angularcss:combobox-open-change="state.open=$event.detail.open"
ng-on-angularcss:combobox-select="state.selected=$event.detail.value; state.query=$event.detail.value; state.open=false"
>
<header>
<input
aria-label="State framework"
ng-model="state.query"
placeholder="Select a framework"
/>
<button
type="button"
aria-label="Show state frameworks"
value="toggle"
></button>
</header>
<aside aria-label="State framework options">
<p>No items found.</p>
<div>
<ul>
<li
ng-repeat="option in stateOptions | filter:state.query"
data-value="{{ option.label }}"
ng-attr-aria-disabled="{{ option.disabled }}"
ng-attr-aria-selected="{{ state.selected === option.label }}"
>
{{ option.label }}
</li>
<li
ng-if="state.showAstro"
data-value="Astro"
ng-attr-aria-selected="{{ state.selected === 'Astro' }}"
>
Astro
</li>
</ul>
</div>
</aside>
</div>
<output class="combobox-state-output" aria-live="polite">
Selected: <span ng-bind="state.selected"></span>. Popup:
<span ng-bind="state.open ? 'open' : 'closed'"></span>. Astro:
<span ng-bind="state.showAstro ? 'shown' : 'hidden'"></span>.
</output>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-combobox]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
A combobox root requires one input and one options surface. The root directive inspects semantic headers, sections, lists, options, fieldsets, and buttons; no child directives or anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-activedescendant | Output | ID of the active option while focus remains on the composite control. |
aria-autocomplete | Input/output | How a text control presents completion suggestions. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-disabled | Input/output | Semantic disabled state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-haspopup | Output | Type of popup controlled by the trigger. |
aria-hidden | Input/output | Whether generated or collapsed content is hidden from assistive technology. |
aria-invalid | Input | Validation state exposed to assistive technology and CSS. |
aria-label | Input/output | Accessible name when visible text is insufficient. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
aria-multiselectable | Output | Whether the composite allows multiple selected items. |
aria-orientation | Output | Interaction axis exposed to assistive technology. |
aria-selected | Input/output | Selected item state. |
auto-highlight | Input | Highlights the first enabled result when the popup opens or filters change. |
data-highlighted | Output | Current option highlighted for keyboard selection. |
data-value | Input | Application value reported when the corresponding option is selected. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
hidden | Input | Native visibility state observed when finding available items. |
multiple | Input | Keeps the popup open and reports selections for an application-owned collection. |
open | Input/output | Initial or externally synchronized disclosure state. |
required | Input | Marks a native form value as required. |
role | Output | Explicit semantic role when native HTML does not provide one. |
side | Output | Physical placement: left, top, bottom, or right. |
tabindex | Output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--combobox-anchor-width | Component styling variable. |
--combobox-content-top | Component styling variable. |
DOM events
angularcss:combobox-clearangularcss:combobox-open-changeangularcss:combobox-remove-lastangularcss:combobox-select
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
The directive owns disclosure, collision-aware placement, active-descendant navigation, enabled-option boundaries, Escape and outside dismissal, and selection, clear, remove-last, and open-change signaling. AngularTS remains responsible for query filtering, selected values and collections, controlled open state, validation, and structural bindings such as ng-repeat, ng-if, and ng-model.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the input an accessible name. The input exposes combobox, expanded, controls, autocomplete, invalid, disabled, and active-descendant state connected to a listbox. Arrow keys, Home, End, Enter, Escape, and Tab operate on enabled visible options; labeled groups retain group relationships, multiple listboxes expose aria-multiselectable, and text direction is mirrored to the popup.
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 [ng-combobox], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.4 - command
Command palette layout
Build a searchable command menu with one ng-command root and semantic child
elements identified by command part classes. AngularTS owns query filtering and
command execution. Command follows the rendered result DOM and supplies listbox
relationships, active-descendant navigation, disabled skipping, and
scroll-to-active behavior.
<section ng-command variant="surface" aria-label="Command menu">
<header>
<label>
<span aria-hidden="true"><!-- search icon --></span>
<input
aria-label="Search commands"
ng-model="query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h2>Suggestions</h2>
<button
type="button"
ng-repeat="command in commands | filter:query"
ng-click="selected=command.label"
>
<span ng-bind="command.label"></span>
<kbd ng-bind="command.shortcut"></kbd>
</button>
</section>
</div>
</section>
Use aria-disabled="true" or native disabled state for unavailable options.
Arrow keys wrap through enabled rendered options; Home and End move to the
boundaries; Enter activates the current option through its ordinary click
handler. Pointer movement updates the same active state.
For a modal palette, place the ng-command root inside a native dialog within
a .dialog wrapper. Use native invoker and close commands to open and close it.
The browser handles modal focus, Escape, configured light dismissal, and focus
restoration. Application
shortcuts such as Ctrl J remain AngularTS ng-keydown expressions.
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 Command</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="commandState={query:'',selected:''}; suggestions=[{label:'Calendar',icon:'calendar',disabled:false},{label:'Search Emoji',icon:'smile',disabled:false},{label:'Calculator',icon:'calculator',disabled:true}]; settings=[{label:'Profile',shortcut:'⌘P',icon:'user'},{label:'Billing',shortcut:'⌘B',icon:'credit-card'},{label:'Settings',shortcut:'⌘S',icon:'settings'}]"
data-example="command-demo"
>
<main class="visual-example">
<section
id="command-demo"
ng-command
variant="surface"
aria-label="Command menu"
>
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search commands"
placeholder="Type a command or search..."
ng-model="commandState.query"
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h2>Suggestions</h2>
<button
type="button"
ng-repeat="item in suggestions | filter:commandState.query"
ng-attr-aria-disabled="{{ item.disabled }}"
ng-click="commandState.selected=item.label"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="8"></circle>
<path d="M8 12h8"></path>
</svg>
<span ng-bind="item.label"></span>
</button>
</section>
<hr />
<section>
<h2>Settings</h2>
<button
type="button"
ng-repeat="item in settings | filter:commandState.query"
ng-click="commandState.selected=item.label"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21a8 8 0 0 1 16 0"></path>
</svg>
<span ng-bind="item.label"></span>
<kbd ng-bind="item.shortcut"></kbd>
</button>
</section>
</div>
</section>
<output class="visually-hidden" aria-live="polite">
Selected:
<span ng-bind="commandState.selected || 'None'"></span>
</output>
</main>
</body>
</html>
Dialog Workflows
Basic, grouped, shortcut-label, and application-owned Ctrl J dialog references
are functional packaged examples.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Command 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>
<script src="../../js/command-demo.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="basic={query:'',selected:''}; grouped={query:'',selected:''}; shortcuts={query:'',selected:''}; shortcutDialog={query:'',selected:''}; suggestions=['Calendar','Search Emoji','Calculator']; settings=[{label:'Profile',shortcut:'⌘P'},{label:'Billing',shortcut:'⌘B'},{label:'Settings',shortcut:'⌘S'}]"
data-example="command-basic command-dialog command-groups command-shortcuts"
>
<main class="command-dialog-workflows visual-example">
<section class="command-dialog-workflow">
<button
type="button"
variant="outline"
aria-controls="basic-command-dialog-content"
commandfor="basic-command-dialog-content"
command="show-modal"
>
Open Menu
</button>
<section id="basic-command-dialog" class="command-dialog-shell dialog">
<dialog
id="basic-command-dialog-content"
closedby="any"
aria-labelledby="basic-command-dialog-title"
aria-describedby="basic-command-dialog-description"
>
<header class="visually-hidden">
<h2 id="basic-command-dialog-title">Command Palette</h2>
<p id="basic-command-dialog-description">
Search for a command to run.
</p>
</header>
<section ng-command aria-label="Basic command menu">
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search basic commands"
ng-model="basic.query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h3>Suggestions</h3>
<button
ng-repeat="item in suggestions | filter:basic.query"
type="button"
ng-click="basic.selected=item"
commandfor="basic-command-dialog-content"
command="close"
>
<span ng-bind="item"></span>
</button>
</section>
</div>
</section>
</dialog>
</section>
<output class="command-workflow-output" aria-live="polite">
Basic: <span ng-bind="basic.selected || 'None'"></span>
</output>
</section>
<section class="command-dialog-workflow">
<button
type="button"
variant="outline"
aria-controls="groups-command-dialog-content"
commandfor="groups-command-dialog-content"
command="show-modal"
>
Open Grouped Menu
</button>
<section id="groups-command-dialog" class="command-dialog-shell dialog">
<dialog
id="groups-command-dialog-content"
closedby="any"
aria-labelledby="groups-command-dialog-title"
aria-describedby="groups-command-dialog-description"
>
<header class="visually-hidden">
<h2 id="groups-command-dialog-title">Grouped Command Palette</h2>
<p id="groups-command-dialog-description">
Search grouped application commands.
</p>
</header>
<section ng-command aria-label="Grouped command menu">
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search grouped commands"
ng-model="grouped.query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h3>Suggestions</h3>
<button
ng-repeat="item in suggestions | filter:grouped.query"
type="button"
ng-click="grouped.selected=item"
commandfor="groups-command-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="8"></circle>
</svg>
<span ng-bind="item"></span>
</button>
</section>
<hr />
<section>
<h3>Settings</h3>
<button
ng-repeat="item in settings | filter:grouped.query"
type="button"
ng-click="grouped.selected=item.label"
commandfor="groups-command-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21a8 8 0 0 1 16 0"></path>
</svg>
<span ng-bind="item.label"></span>
<kbd ng-bind="item.shortcut"></kbd>
</button>
</section>
</div>
</section>
</dialog>
</section>
<output class="command-workflow-output" aria-live="polite">
Grouped: <span ng-bind="grouped.selected || 'None'"></span>
</output>
</section>
<section class="command-dialog-workflow">
<button
type="button"
variant="outline"
aria-controls="shortcuts-command-dialog-content"
commandfor="shortcuts-command-dialog-content"
command="show-modal"
>
Open Shortcuts
</button>
<section
id="shortcuts-command-dialog"
class="command-dialog-shell dialog"
>
<dialog
id="shortcuts-command-dialog-content"
closedby="any"
aria-labelledby="shortcuts-command-dialog-title"
aria-describedby="shortcuts-command-dialog-description"
>
<header class="visually-hidden">
<h2 id="shortcuts-command-dialog-title">Command Shortcuts</h2>
<p id="shortcuts-command-dialog-description">
Search settings commands.
</p>
</header>
<section ng-command aria-label="Shortcut command menu">
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search shortcut commands"
ng-model="shortcuts.query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h3>Settings</h3>
<button
ng-repeat="item in settings | filter:shortcuts.query"
type="button"
ng-click="shortcuts.selected=item.label"
commandfor="shortcuts-command-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21a8 8 0 0 1 16 0"></path>
</svg>
<span ng-bind="item.label"></span>
<kbd ng-bind="item.shortcut"></kbd>
</button>
</section>
</div>
</section>
</dialog>
</section>
<output class="command-workflow-output" aria-live="polite">
Shortcut: <span ng-bind="shortcuts.selected || 'None'"></span>
</output>
</section>
<section class="command-dialog-workflow command-shortcut-workflow">
<p>Press <kbd>Ctrl J</kbd></p>
<section
id="keyboard-command-dialog"
class="command-dialog-shell dialog"
>
<dialog
id="keyboard-command-dialog-content"
closedby="any"
aria-labelledby="keyboard-command-dialog-title"
aria-describedby="keyboard-command-dialog-description"
>
<header class="visually-hidden">
<h2 id="keyboard-command-dialog-title">
Keyboard Command Palette
</h2>
<p id="keyboard-command-dialog-description">
Search for a command to run.
</p>
</header>
<section ng-command aria-label="Keyboard command menu">
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search keyboard commands"
ng-model="shortcutDialog.query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section>
<h3>Suggestions</h3>
<button
ng-repeat="item in suggestions | filter:shortcutDialog.query"
type="button"
ng-click="shortcutDialog.selected=item"
commandfor="keyboard-command-dialog-content"
command="close"
>
<span ng-bind="item"></span>
</button>
</section>
<hr />
<section>
<h3>Settings</h3>
<button
ng-repeat="item in settings | filter:shortcutDialog.query"
type="button"
ng-click="shortcutDialog.selected=item.label"
commandfor="keyboard-command-dialog-content"
command="close"
>
<span ng-bind="item.label"></span>
<kbd ng-bind="item.shortcut"></kbd>
</button>
</section>
</div>
</section>
</dialog>
</section>
<output class="command-workflow-output" aria-live="polite">
Keyboard:
<span ng-bind="shortcutDialog.selected || 'None'"></span>
</output>
</section>
</main>
</body>
</html>
The full 23-item reference inventory demonstrates the 288px list constraint,
keyboard scroll-to-active behavior, filtering, and selection.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Command 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="scroll={query:'',selected:''}; commandGroups=[{label:'Navigation',items:[{label:'Home',shortcut:'⌘H'},{label:'Inbox',shortcut:'⌘I'},{label:'Documents',shortcut:'⌘D'},{label:'Folders',shortcut:'⌘F'}]},{label:'Actions',items:[{label:'New File',shortcut:'⌘N'},{label:'New Folder',shortcut:'⇧⌘N'},{label:'Copy',shortcut:'⌘C'},{label:'Cut',shortcut:'⌘X'},{label:'Paste',shortcut:'⌘V'},{label:'Delete',shortcut:'⌫'}]},{label:'View',items:[{label:'Grid View',shortcut:''},{label:'List View',shortcut:''},{label:'Zoom In',shortcut:'⌘+'},{label:'Zoom Out',shortcut:'⌘-'}]},{label:'Account',items:[{label:'Profile',shortcut:'⌘P'},{label:'Billing',shortcut:'⌘B'},{label:'Settings',shortcut:'⌘S'},{label:'Notifications',shortcut:''},{label:'Help & Support',shortcut:''}]},{label:'Tools',items:[{label:'Calculator',shortcut:''},{label:'Calendar',shortcut:''},{label:'Image Editor',shortcut:''},{label:'Code Editor',shortcut:''}]}]"
data-example="command-scrollable"
>
<main class="command-scrollable-demo visual-example">
<button
type="button"
variant="outline"
aria-controls="scrollable-command-dialog-content"
commandfor="scrollable-command-dialog-content"
command="show-modal"
>
Open Menu
</button>
<section
id="scrollable-command-dialog"
class="command-dialog-shell dialog"
>
<dialog
id="scrollable-command-dialog-content"
closedby="any"
aria-labelledby="scrollable-command-dialog-title"
aria-describedby="scrollable-command-dialog-description"
>
<header class="visually-hidden">
<h2 id="scrollable-command-dialog-title">
Scrollable Command Palette
</h2>
<p id="scrollable-command-dialog-description">
Search all application commands.
</p>
</header>
<section ng-command aria-label="Scrollable command menu">
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
aria-label="Search all commands"
ng-model="scroll.query"
placeholder="Type a command or search..."
/>
</label>
</header>
<div>
<p>No results found.</p>
<section ng-repeat="group in commandGroups">
<h3 ng-bind="group.label"></h3>
<button
ng-repeat="item in group.items | filter:scroll.query"
type="button"
ng-click="scroll.selected=item.label"
commandfor="scrollable-command-dialog-content"
command="close"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M6 2h9l3 3v17H6z"></path>
<path d="M14 2v4h4"></path>
</svg>
<span ng-bind="item.label"></span>
<kbd ng-if="item.shortcut" ng-bind="item.shortcut"></kbd>
</button>
<hr />
</section>
</div>
</section>
</dialog>
</section>
<output class="command-workflow-output" aria-live="polite">
Selected: <span ng-bind="scroll.selected || 'None'"></span>
</output>
</main>
</body>
</html>
RTL
Logical icon, text, shortcut, active-item, and keyboard order are preserved in
an Arabic command surface.
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 Command 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="rtlCommand={query:'',selected:''}; rtlSuggestions=[{label:'التقويم',disabled:false},{label:'البحث عن الرموز التعبيرية',disabled:false},{label:'الآلة الحاسبة',disabled:true}]; rtlSettings=[{label:'الملف الشخصي',shortcut:'⌘P'},{label:'الفوترة',shortcut:'⌘B'},{label:'الإعدادات',shortcut:'⌘S'}]"
data-example="command-rtl"
>
<main class="visual-example">
<section
id="rtl-command"
ng-command
variant="surface"
aria-label="قائمة الأوامر"
>
<header>
<label>
<span aria-hidden="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</span>
<input
dir="rtl"
aria-label="البحث في الأوامر"
ng-model="rtlCommand.query"
placeholder="اكتب أمرًا أو ابحث..."
/>
</label>
</header>
<div>
<p>لم يتم العثور على نتائج.</p>
<section>
<h2>اقتراحات</h2>
<button
type="button"
ng-repeat="item in rtlSuggestions | filter:rtlCommand.query"
ng-attr-aria-disabled="{{ item.disabled }}"
ng-click="rtlCommand.selected=item.label"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="8"></circle>
</svg>
<span ng-bind="item.label"></span>
</button>
</section>
<hr />
<section>
<h2>الإعدادات</h2>
<button
type="button"
ng-repeat="item in rtlSettings | filter:rtlCommand.query"
ng-click="rtlCommand.selected=item.label"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="8" r="4"></circle>
<path d="M4 21a8 8 0 0 1 16 0"></path>
</svg>
<span ng-bind="item.label"></span>
<kbd ng-bind="item.shortcut"></kbd>
</button>
</section>
</div>
</section>
<output class="visually-hidden" aria-live="polite">
المحدد: <span ng-bind="rtlCommand.selected || 'لا شيء'"></span>
</output>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-command]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
A command root requires one input and a result container. The root directive inspects semantic headers, sections, headings, buttons, separators, and keyboard hints; no child directives or anatomy classes are required. Compose modal palettes from Dialog.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-activedescendant | Output | ID of the active option while focus remains on the composite control. |
aria-autocomplete | Input/output | How a text control presents completion suggestions. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-disabled | Input/output | Semantic disabled state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-hidden | Input/output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
aria-orientation | Output | Interaction axis exposed to assistive technology. |
aria-selected | Input/output | Selected item state. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
hidden | Input | Native visibility state observed when finding available items. |
role | Output | Explicit semantic role when native HTML does not provide one. |
tabindex | Output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive follows the application-rendered result DOM and owns active-descendant navigation, enabled-option wrapping and boundaries, pointer synchronization, Enter activation through the authored click handler, semantic group and empty state, and scroll-to-active behavior. AngularTS remains responsible for query filtering, command execution, result data, structural bindings, and application keyboard shortcuts. Dialog remains responsible for modal disclosure, focus trapping, Escape, outside dismissal, and focus restoration.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the search input and command surface useful accessible names. The input is connected to a listbox through aria-controls and aria-activedescendant; rendered options expose selected and disabled state, labeled groups retain group relationships, separators are decorative structure, and shortcut labels are hidden from repeated announcement. A modal composition must include an accessible Dialog title and description.
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 [ng-command], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.5 - context-menu
Context menu surface and items
Use a semantic trigger and content surface. AngularCSS owns right-click and
keyboard disclosure, pointer placement, menu focus, and submenu navigation;
AngularTS owns actions and checkbox or radio values.
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Browser actions">
<button ng-click="reload()">Reload</button>
<button
aria-checked="{{ showBookmarks }}"
ng-click="showBookmarks=!showBookmarks"
>
Show Bookmarks Bar
</button>
</menu>
</div>
Ordinary click is left to the authored trigger. Right-click, Shift F10, and the
Context Menu key open this component.
Basic And Submenu
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 Context Menu</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="lastAction='None'"
data-example="context-menu-basic context-menu-demo context-menu-submenu"
>
<main class="visual-example">
<div id="context-menu-demo" ng-context-menu>
<div>Right click here</div>
<menu aria-label="Browser actions">
<section>
<button ng-click="lastAction='Back'">
Back
<kbd>Alt+Left</kbd>
</button>
<button disabled>
Forward
<kbd>Alt+Right</kbd>
</button>
<button ng-click="lastAction='Reload'">
Reload
<kbd>Ctrl+R</kbd>
</button>
</section>
<hr />
<section>
<button ng-click="lastAction='Save'">
Save
<kbd>Ctrl+S</kbd>
</button>
</section>
<details>
<summary>More Tools</summary>
<menu>
<section>
<button ng-click="lastAction='Save Page'">Save Page...</button>
<button ng-click="lastAction='Create Shortcut'">
Create Shortcut...
</button>
<button ng-click="lastAction='Name Window'">
Name Window...
</button>
</section>
<hr />
<button ng-click="lastAction='Developer Tools'">
Developer Tools
</button>
</menu>
</details>
<hr />
<button variant="destructive" ng-click="lastAction='Delete'">
Delete
</button>
</menu>
</div>
<output class="context-menu-output" aria-live="polite">
Last action: <span ng-bind="lastAction"></span>
</output>
</main>
</body>
</html>
Content And State
Icons, destructive actions, groups, shortcuts, checkbox values, and radio values
are functional packaged scenarios.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu 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="action='None'; view={bookmarks:true,urls:false}; person='pedro'; theme='light'"
data-example="context-menu-checkboxes context-menu-destructive context-menu-groups context-menu-icons context-menu-radio context-menu-shortcuts"
>
<main class="context-menu-workflow-grid visual-example">
<section class="context-menu-workflow" aria-labelledby="icons-title">
<h2 id="icons-title">Icons and destructive action</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Editing actions">
<section>
<button ng-click="action='Copy'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="9" y="9" width="11" height="11" rx="2"></rect>
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
></path>
</svg>
Copy
</button>
<button ng-click="action='Cut'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="6" cy="6" r="3"></circle>
<circle cx="6" cy="18" r="3"></circle>
<path d="m20 4-8.5 8.5"></path>
<path d="m14.5 14.5 5.5 5.5"></path>
</svg>
Cut
</button>
<button ng-click="action='Paste'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="5" y="4" width="14" height="18" rx="2"></rect>
<path d="M9 4.5V2h6v2.5"></path>
</svg>
Paste
</button>
</section>
<hr />
<button variant="destructive" ng-click="action='Delete'">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M3 6h18"></path>
<path d="M8 6V4h8v2"></path>
<path d="m19 6-1 15H6L5 6"></path>
</svg>
Delete
</button>
</menu>
</div>
<output>Action: <span ng-bind="action"></span></output>
</section>
<section class="context-menu-workflow" aria-labelledby="groups-title">
<h2 id="groups-title">Groups and shortcuts</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="File actions">
<section>
<h3>File</h3>
<button>New File <kbd>Ctrl+N</kbd></button>
<button>Open File <kbd>Ctrl+O</kbd></button>
<button>Save <kbd>Ctrl+S</kbd></button>
</section>
<hr />
<section>
<h3>Edit</h3>
<button>Undo <kbd>Ctrl+Z</kbd></button>
<button disabled>Redo <kbd>Shift+Ctrl+Z</kbd></button>
</section>
</menu>
</div>
</section>
<section class="context-menu-workflow" aria-labelledby="checkbox-title">
<h2 id="checkbox-title">Checkboxes</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="View options">
<button
aria-checked="{{ view.bookmarks }}"
ng-click="view.bookmarks=!view.bookmarks"
>
Show Bookmarks Bar
</button>
<button
aria-checked="{{ view.urls }}"
ng-click="view.urls=!view.urls"
>
Show Full URLs
</button>
</menu>
</div>
<output>
Bookmarks: <span ng-bind="view.bookmarks ? 'On' : 'Off'"></span>
</output>
</section>
<section class="context-menu-workflow" aria-labelledby="radio-title">
<h2 id="radio-title">Radio groups</h2>
<div ng-context-menu>
<div>Right click here</div>
<menu aria-label="Profile and theme">
<section>
<h3>People</h3>
<fieldset aria-label="People">
<button
aria-checked="{{ person === 'pedro' }}"
ng-click="person='pedro'"
>
Pedro Duarte
</button>
<button
aria-checked="{{ person === 'colm' }}"
ng-click="person='colm'"
>
Colm Tuite
</button>
</fieldset>
</section>
<hr />
<section>
<h3>Theme</h3>
<fieldset aria-label="Theme">
<button
aria-checked="{{ theme === 'light' }}"
ng-click="theme='light'"
>
Light
</button>
<button
aria-checked="{{ theme === 'dark' }}"
ng-click="theme='dark'"
>
Dark
</button>
<button
aria-checked="{{ theme === 'system' }}"
ng-click="theme='system'"
>
System
</button>
</fieldset>
</section>
</menu>
</div>
<output>
Person: <span ng-bind="person"></span>; Theme:
<span ng-bind="theme"></span>
</output>
</section>
</main>
</body>
</html>
Placement
The six physical and logical side options anchor to the invocation point and
remain constrained to the viewport.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Context Menu 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 data-example="context-menu-sides">
<main class="context-menu-sides visual-example">
<div
ng-context-menu
ng-repeat="side in ['inline-start','left','top','bottom','right','inline-end']"
>
<div ng-bind="side"></div>
<menu side="{{ side }}" aria-label="{{ side }} actions">
<button>Back</button>
<button>Forward</button>
<button>Reload</button>
</menu>
</div>
</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 Context Menu 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="lastAction='لا شيء'"
data-example="context-menu-rtl"
>
<main class="visual-example">
<div ng-context-menu>
<div>انقر بزر الفأرة الأيمن هنا</div>
<menu aria-label="إجراءات المتصفح">
<section>
<button ng-click="lastAction='رجوع'">
رجوع
<kbd>Alt+Right</kbd>
</button>
<button disabled>
للأمام
<kbd>Alt+Left</kbd>
</button>
<button ng-click="lastAction='إعادة تحميل'">
إعادة تحميل
<kbd>Ctrl+R</kbd>
</button>
</section>
<hr />
<details>
<summary>المزيد من الأدوات</summary>
<menu>
<button ng-click="lastAction='حفظ الصفحة'">حفظ الصفحة...</button>
<button ng-click="lastAction='أدوات المطور'">أدوات المطور</button>
</menu>
</details>
</menu>
</div>
<output class="context-menu-output" aria-live="polite">
الإجراء الأخير: <span ng-bind="lastAction"></span>
</output>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-context-menu]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
A context menu root requires one focusable trigger and one menu. The root directive inspects semantic sections, fieldsets, buttons, separators, keyboard hints, and nested details; no child directives or anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Input/output | Cross-axis alignment: start, center, or end. |
align-offset | Input | Additional alignment offset in CSS pixels. |
aria-checked | Input/output | ARIA relationship or state. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-disabled | Input/output | Semantic disabled state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-haspopup | Output | Type of popup controlled by the trigger. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
open | Input | Initial or controlled open state. |
role | Output | Explicit semantic role when native HTML does not provide one. |
side | Input/output | Physical placement: left, top, bottom, or right. |
side-offset | Input | Distance from the invocation point in CSS pixels. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--context-menu-available-height | Component styling variable. |
--context-menu-left | Component styling variable. |
--context-menu-top | Component styling variable. |
DOM events
angularcss:context-menu-select
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
The directive owns right-click and keyboard disclosure, cursor-relative side placement with viewport collision constraints, menu and submenu focus movement, disabled-item skipping, Escape and outside dismissal, direction-aware submenu keys, semantic roles, and open-state reflection. AngularTS remains responsible for command execution, checkbox and radio values, controlled application state, and structural rendering.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the trigger and menu useful accessible names. The trigger exposes aria-haspopup, aria-controls, and expanded state; items receive menuitem, menuitemcheckbox, or menuitemradio roles; groups and separators remain semantic; disabled items are skipped. Shift+F10 or the Context Menu key opens from the keyboard, arrow keys move focus, logical submenu keys follow text direction, and Escape restores focus.
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 [ng-context-menu], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.6 - dropdown-menu
Menu opened from a trigger button
Use ng-dropdown-menu on a wrapper with a trigger button and a native menu.
<div ng-dropdown-menu>
<button type="button">Options</button>
<menu>
<a href="#new">New Task</a>
<a href="#edit">Edit Task</a>
<a href="#delete">Delete Task</a>
</menu>
</div>
The directive adds the required menu roles and manages aria-expanded,
aria-controls, outside-click close, Escape close, and arrow-key focus
movement. It does not publish scope methods or own AngularTS application state.
If the menu needs external control, bind the wrapper’s concise open attribute
from AngularTS state.
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 Dropdown Menu</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="menuState={toolbar:true,density:'comfortable'}"
data-example="dropdown-menu-complex dropdown-menu-demo"
>
<div ng-dropdown-menu class="visual-example">
<button type="button">Options</button>
<menu style="--menu-width: 11rem">
<section>
<h3>Project</h3>
<button>New task <kbd>Ctrl+N</kbd></button>
<button>Edit task</button>
</section>
<hr />
<button
aria-checked="{{ menuState.toolbar }}"
ng-click="menuState.toolbar=!menuState.toolbar"
>
Show toolbar
</button>
<fieldset aria-label="Density">
<button
aria-checked="{{ menuState.density === 'comfortable' }}"
ng-click="menuState.density='comfortable'"
>
Comfortable
</button>
<button
aria-checked="{{ menuState.density === 'compact' }}"
ng-click="menuState.density='compact'"
>
Compact
</button>
</fieldset>
<details>
<summary>Share</summary>
<menu>
<button>Copy link</button>
<button>Email link</button>
</menu>
</details>
</menu>
</div>
</body>
</html>
Reference workflows
The workflow page covers basic and dynamically inserted items, an avatar
trigger, AngularTS-owned checkbox and radio state, shortcuts, destructive items,
submenus, right-to-left direction, and disabled triggers.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Dropdown Menu 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="dropdownDemo={archive:false,email:true,sms:false,position:'bottom',disabled:false}"
data-example="dropdown-menu-avatar dropdown-menu-basic dropdown-menu-checkboxes dropdown-menu-checkboxes-icons dropdown-menu-destructive dropdown-menu-icons dropdown-menu-radio-group dropdown-menu-radio-icons dropdown-menu-rtl dropdown-menu-shortcuts dropdown-menu-submenu"
>
<main class="dropdown-workflow-grid">
<section class="dropdown-workflow" aria-labelledby="dropdown-basic-title">
<h2 id="dropdown-basic-title">Basic and dynamic items</h2>
<div class="dropdown-workflow-actions">
<button
type="button"
variant="outline"
ng-click="dropdownDemo.archive=true"
ng-disabled="dropdownDemo.archive"
>
{{ dropdownDemo.archive ? 'Archive added' : 'Add archive item' }}
</button>
<div ng-dropdown-menu aria-label="Account commands">
<button type="button">Open</button>
<menu>
<section>
<h3>My Account</h3>
<button>Profile</button>
<button>Billing</button>
<button>Settings</button>
</section>
<hr />
<button>Support</button>
<button disabled>API</button>
<button id="dropdown-archive-item" ng-if="dropdownDemo.archive">
Archive
</button>
</menu>
</div>
</div>
</section>
<section
class="dropdown-workflow"
aria-labelledby="dropdown-avatar-title"
>
<h2 id="dropdown-avatar-title">Avatar trigger</h2>
<div ng-dropdown-menu class="dropdown-avatar-demo">
<button
type="button"
size="icon"
variant="ghost"
aria-label="Open account menu"
>
<span class="avatar">
<img src="../../images/avatars/01.png" alt="Jane Doe" />
<span>JD</span>
</span>
</button>
<menu align="end">
<section>
<button>Account</button>
<button>Billing</button>
<button>Notifications</button>
</section>
<hr />
<button variant="destructive">Sign Out</button>
</menu>
</div>
</section>
<section
class="dropdown-workflow dropdown-workflow-menu-tall"
aria-labelledby="dropdown-preferences-title"
>
<h2 id="dropdown-preferences-title">Preferences</h2>
<div ng-dropdown-menu>
<button type="button">Notifications</button>
<menu style="--menu-width: 13rem">
<section>
<h3>Notification Preferences</h3>
<button
aria-checked="{{ dropdownDemo.email }}"
ng-click="dropdownDemo.email=!dropdownDemo.email"
>
Email notifications
</button>
<button
aria-checked="{{ dropdownDemo.sms }}"
ng-click="dropdownDemo.sms=!dropdownDemo.sms"
>
SMS notifications
</button>
</section>
<hr />
<fieldset aria-label="Menu position">
<h3>Position</h3>
<button
aria-checked="{{ dropdownDemo.position === 'top' }}"
ng-click="dropdownDemo.position='top'"
>
Top
</button>
<button
aria-checked="{{ dropdownDemo.position === 'bottom' }}"
ng-click="dropdownDemo.position='bottom'"
>
Bottom
</button>
</fieldset>
</menu>
</div>
</section>
<section
class="dropdown-workflow dropdown-workflow-menu-tall"
aria-labelledby="dropdown-actions-title"
>
<h2 id="dropdown-actions-title">Actions and submenu</h2>
<div ng-dropdown-menu>
<button type="button">Actions</button>
<menu style="--menu-width: 13rem">
<section>
<button>
Edit
<kbd>Ctrl+E</kbd>
</button>
<button>
Share
<kbd>Ctrl+S</kbd>
</button>
<details>
<summary>Invite users</summary>
<menu>
<button>Email</button>
<button>Message</button>
<hr />
<button>More options</button>
</menu>
</details>
</section>
<hr />
<button variant="destructive">Delete</button>
</menu>
</div>
</section>
<section
class="dropdown-workflow dropdown-workflow-wide dropdown-workflow-rtl"
dir="rtl"
lang="ar"
aria-labelledby="dropdown-rtl-title"
>
<div class="dropdown-workflow-heading">
<h2 id="dropdown-rtl-title">اتجاه من اليمين إلى اليسار</h2>
<label>
<input type="checkbox" ng-model="dropdownDemo.disabled" />
تعطيل القائمة
</label>
</div>
<div ng-dropdown-menu aria-label="Arabic account menu">
<button type="button" ng-disabled="dropdownDemo.disabled">
افتح القائمة
</button>
<menu>
<h3>الحساب</h3>
<button>الملف الشخصي</button>
<button>الإعدادات</button>
<hr />
<button variant="destructive">تسجيل الخروج</button>
</menu>
</div>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-dropdown-menu]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Use native elements for authored structure. Component classes are optional visual hooks when an HTML relationship is not specific enough.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Input | Cross-axis alignment: start, center, or end. |
align-offset | Input | Additional alignment offset in CSS pixels. |
aria-checked | Input/output | ARIA relationship or state. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-haspopup | Input/output | Type of popup controlled by the trigger. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
dir | Input | Text and interaction direction: ltr or rtl. |
open | Input | Initial or controlled open state. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
side | Input | Physical placement: left, top, bottom, or right. |
side-offset | Input | Distance from the trigger in CSS pixels. |
size | Input | Visual size token supported by the component stylesheet. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--dropdown-menu-available-height | Component styling variable. |
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
The directive owns menu disclosure, focus movement, escape handling, and outside-click closure. Command execution and checked values remain application-owned.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Triggers expose popup and expanded state. Arrow keys move among enabled items, Escape closes the menu, and focus returns to the invoking control when appropriate.
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 [ng-dropdown-menu], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.7 - hover-card
Rich hover preview cards
Use ng-hover-card with a keyboard-focusable trigger and preview content.
Pointer disclosure honors optional open-delay and close-delay values in
milliseconds. Set side on the content to left, top, bottom, or right.
<span ng-hover-card open-delay="100" close-delay="100">
<a href="#">@angularcss</a>
<aside side="bottom">Preview</aside>
</span>
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 Hover Card</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="hover-card-demo">
<main class="visual-example">
<span ng-hover-card open-delay="10" close-delay="100">
<button type="button" variant="link">Hover Here</button>
<aside>
<h3>@nextjs</h3>
<p>The React Framework - created and maintained by @vercel.</p>
<footer>Joined December 2021</footer>
</aside>
</span>
</main>
</body>
</html>
Physical 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 Hover Card 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="hover-card-sides">
<main class="hover-card-workflow">
<header class="hover-card-workflow-header">
<h2>Physical sides</h2>
</header>
<div class="hover-card-side-grid">
<section class="hover-card-stage hover-card-stage-left">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">Left</button>
<aside side="left">
<h3>Hover Card</h3>
<p>This hover card appears on the left side of the trigger.</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-top">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">Top</button>
<aside side="top">
<h3>Hover Card</h3>
<p>This hover card appears on the top side of the trigger.</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-bottom">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">Bottom</button>
<aside side="bottom">
<h3>Hover Card</h3>
<p>This hover card appears on the bottom side of the trigger.</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-right">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">Right</button>
<aside side="right">
<h3>Hover Card</h3>
<p>This hover card appears on the right side of the trigger.</p>
</aside>
</span>
</section>
</div>
<footer class="hover-card-disabled-example">
<span ng-hover-card open-delay="0" close-delay="0">
<button type="button" variant="outline" disabled>Disabled</button>
<aside>
<p>Unavailable preview</p>
</aside>
</span>
</footer>
</main>
</body>
</html>
Right-to-left
Physical left and right placement stays physical while text direction and
content alignment follow the nearest authored dir attribute.
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 Hover Card 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 data-example="hover-card-rtl">
<main class="hover-card-workflow" dir="rtl">
<header class="hover-card-workflow-header">
<h2>الجوانب الفعلية</h2>
</header>
<div class="hover-card-side-grid">
<section class="hover-card-stage hover-card-stage-left">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">يسار</button>
<aside side="left">
<h3>سماعات لاسلكية</h3>
<p>٩٩.٩٩ $</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-top">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">أعلى</button>
<aside side="top">
<h3>سماعات لاسلكية</h3>
<p>٩٩.٩٩ $</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-bottom">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">أسفل</button>
<aside side="bottom">
<h3>سماعات لاسلكية</h3>
<p>٩٩.٩٩ $</p>
</aside>
</span>
</section>
<section class="hover-card-stage hover-card-stage-right">
<span ng-hover-card open-delay="20" close-delay="100">
<button type="button" variant="outline">يمين</button>
<aside side="right">
<h3>سماعات لاسلكية</h3>
<p>٩٩.٩٩ $</p>
</aside>
</span>
</section>
</div>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-hover-card]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
A keyboard-focusable trigger and one preview content element are required. Title and description slots are optional semantic styling hooks inside the preview.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-controls | Output | ID of the element controlled by a trigger. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
close-delay | Input | Pointer close delay in milliseconds. |
open | Input | Initial or controlled open state. |
open-delay | Input | Pointer open delay in milliseconds. |
side | Input/output | Physical placement: left, top, bottom, or right. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive owns delayed pointer and focus disclosure, physical side placement, Escape closure, and synchronized open state. It is non-modal and does not trap focus. Applications own preview content and may control the concise authored open attribute.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
The trigger exposes aria-controls and aria-expanded; the preview exposes its hidden state without becoming modal. Keep the trigger keyboard focusable, preserve readable content order, and do not place essential information only inside a hover card.
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 [ng-hover-card], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.8 - menubar
Keyboard-first top-level navigation with open/close menu behavior.
Use ng-menubar around a strip of menu groups. Menu triggers support:
ArrowLeft/ArrowRight to move between menusEnter/Space/ArrowDown to open a menuEscape to close menusHome/End shortcuts when a trigger is focused
<nav ng-menubar aria-label="Application menu">
<section>
<button>File</button>
<menu>
<button>New</button>
<button>Open</button>
</menu>
</section>
<section>
<button>Edit</button>
</section>
</nav>
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 Menubar</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="menubarDemo={bookmarks:false,fullUrls:true,profile:'benoit'}"
data-example="menubar-demo"
>
<main class="visual-example">
<nav ng-menubar aria-label="Browser application menu">
<section>
<button type="button">File</button>
<menu>
<section>
<button type="button">New Tab <kbd>⌘T</kbd></button>
<button type="button">New Window <kbd>⌘N</kbd></button>
<button type="button" disabled>New Incognito Window</button>
</section>
<hr />
<section>
<details>
<summary>Share</summary>
<menu>
<section>
<button type="button">Email link</button>
<button type="button">Messages</button>
<button type="button">Notes</button>
</section>
</menu>
</details>
</section>
<hr />
<section>
<button type="button">Print... <kbd>⌘P</kbd></button>
</section>
</menu>
</section>
<section>
<button type="button">Edit</button>
<menu>
<section>
<button type="button">Undo <kbd>⌘Z</kbd></button>
<button type="button">Redo <kbd>⇧⌘Z</kbd></button>
</section>
<hr />
<section>
<details>
<summary>Find</summary>
<menu>
<button type="button">Search the web</button>
<hr />
<button type="button">Find...</button>
<button type="button">Find Next</button>
<button type="button">Find Previous</button>
</menu>
</details>
</section>
<hr />
<section>
<button type="button">Cut</button>
<button type="button">Copy</button>
<button type="button">Paste</button>
</section>
</menu>
</section>
<section>
<button type="button">View</button>
<menu>
<section>
<button
type="button"
aria-checked="{{ menubarDemo.bookmarks }}"
ng-click="menubarDemo.bookmarks=!menubarDemo.bookmarks"
>
Bookmarks Bar
</button>
<button
type="button"
aria-checked="{{ menubarDemo.fullUrls }}"
ng-click="menubarDemo.fullUrls=!menubarDemo.fullUrls"
>
Full URLs
</button>
</section>
<hr />
<section>
<button type="button" inset>Reload <kbd>⌘R</kbd></button>
<button type="button" inset disabled>
Force Reload <kbd>⇧⌘R</kbd>
</button>
</section>
<hr />
<button type="button" inset>Toggle Fullscreen</button>
<hr />
<button type="button" inset>Hide Sidebar</button>
</menu>
</section>
<section>
<button type="button">Profiles</button>
<menu>
<fieldset aria-label="Active profile">
<button
type="button"
aria-checked="{{ menubarDemo.profile === 'andy' }}"
ng-click="menubarDemo.profile='andy'"
>
Andy
</button>
<button
type="button"
aria-checked="{{ menubarDemo.profile === 'benoit' }}"
ng-click="menubarDemo.profile='benoit'"
>
Benoit
</button>
<button
type="button"
aria-checked="{{ menubarDemo.profile === 'luis' }}"
ng-click="menubarDemo.profile='luis'"
>
Luis
</button>
</fieldset>
<hr />
<button type="button" inset>Edit...</button>
<hr />
<button type="button" inset>Add Profile...</button>
</menu>
</section>
</nav>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-menubar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Each top-level section requires one native button trigger and one menu. The root directive inspects semantic sections, fieldsets, buttons, separators, keyboard hints, and nested details; no child directives or anatomy classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-checked | Input/output | ARIA relationship or state. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-haspopup | Output | Type of popup controlled by the trigger. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
dir | Input | Text and interaction direction: ltr or rtl. |
open | Input | Initial or controlled open state. |
role | Output | Explicit semantic role when native HTML does not provide one. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive owns top-level roving focus, menu and submenu disclosure, enabled-item navigation, Escape and outside-click closure, DOM-order synchronization for dynamically inserted menus, and direction-aware horizontal keys. AngularTS remains responsible for command execution, checkbox and radio values, and structural content such as ng-if.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
The root exposes role="menubar" and keeps one enabled top-level trigger in the tab order. Triggers identify their menus with aria-controls; disabled triggers and items are skipped. Arrow keys follow visual direction, submenu keys remain local to the submenu, and Escape restores focus to the active trigger.
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 [ng-menubar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.9 - navigation-menu
Site navigation with optional flyout content
Navigation menu is exposed as semantic nav markup with list, item, trigger,
link, and content parts.
<nav ng-navigation-menu>
<ul>
<li>
<button>Components</button>
<section>Links</section>
</li>
</ul>
</nav>
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 Navigation Menu</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="navigation-menu-demo">
<main>
<nav ng-navigation-menu aria-label="Primary navigation">
<ul>
<li>
<button type="button">Getting started</button>
<section>
<ul>
<li>
<a href="#introduction">
<strong>Introduction</strong>
<span>Reusable components built with semantic HTML.</span>
</a>
</li>
<li>
<a href="#installation">
<strong>Installation</strong>
<span
>How to install dependencies and structure your app.</span
>
</a>
</li>
<li>
<a href="#typography">
<strong>Typography</strong>
<span>Styles for headings, paragraphs, lists...etc</span>
</a>
</li>
</ul>
</section>
</li>
<li>
<button type="button">Components</button>
<section>
<ul>
<li>
<a href="#alert-dialog">
<strong>Alert Dialog</strong>
<span
>A modal dialog with important content that expects a
response.</span
>
</a>
</li>
<li>
<a href="#hover-card">
<strong>Hover Card</strong>
<span>Preview content available behind a link.</span>
</a>
</li>
<li>
<a href="#progress">
<strong>Progress</strong>
<span>Displays the completion progress of a task.</span>
</a>
</li>
<li>
<a href="#scroll-area">
<strong>Scroll-area</strong>
<span>Visually or semantically separates content.</span>
</a>
</li>
<li>
<a href="#tabs">
<strong>Tabs</strong>
<span>Layered sections displayed one at a time.</span>
</a>
</li>
<li>
<a href="#tooltip">
<strong>Tooltip</strong>
<span>Information shown from keyboard focus or hover.</span>
</a>
</li>
</ul>
</section>
</li>
<li>
<button type="button">With Icon</button>
<section>
<ul>
<li>
<a href="#backlog">
<svg
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 8v4m0 4h.01"></path>
</svg>
Backlog
</a>
</li>
<li>
<a href="#todo">
<svg
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle
cx="12"
cy="12"
r="10"
stroke-dasharray="4 3"
></circle>
</svg>
To Do
</a>
</li>
<li>
<a href="#done">
<svg
aria-hidden="true"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="m8 12 2.5 2.5L16 9"></path>
</svg>
Done
</a>
</li>
</ul>
</section>
</li>
<li>
<a href="#docs">Docs</a>
</li>
</ul>
</nav>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-navigation-menu]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Use a native nav containing one direct list. Each list item may contain either a native link or a native button trigger followed by a semantic section. The root directive needs no child directives or anatomy classes.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
align | Input | Cross-axis alignment: start, center, or end. |
aria-controls | Output | ID of the element controlled by a trigger. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-hidden | Input/output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
open | Input | Initial or controlled open state. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--navigation-menu-content-offset | Component styling variable. |
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
The directive owns site-navigation disclosure, focus restoration, direction-aware arrow movement, dynamic DOM-order synchronization, outside dismissal, and flyout collision handling. Native links continue to own navigation. URLs, routing, current-page state, authored controlled state, and application commands remain AngularTS or application concerns.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use a native nav landmark containing a list. Keep destinations as native links and disclosure controls as native buttons; do not add menu or menuitem roles to site navigation. Triggers expose aria-expanded and aria-controls, direct links remain in horizontal keyboard order, and Escape restores focus to the active trigger.
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 [ng-navigation-menu], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.10 - range-slider
Multiple native range inputs coordinated on one shared track.
Use ng-range-slider only when two or more native range inputs share one visual
track. The parent inspects its direct inputs and computes composite geometry
while every input retains native focus, keyboard, form, and AngularTS model
behavior. Use the Range element for a single value.
<fieldset>
<legend>Price range</legend>
<div ng-range-slider min="0" max="100">
<input
aria-label="Minimum price"
type="range"
min="0"
max="100"
value="25"
/>
<input
aria-label="Maximum price"
type="range"
min="0"
max="100"
value="75"
/>
</div>
</fieldset>
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 Range Slider</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="minimum = 25; maximum = 75"
data-example="slider-demo"
>
<main class="visual-example">
<header>
<label id="price-range-label">Price range</label>
<output>{{ minimum }}-{{ maximum }}</output>
</header>
<div
ng-range-slider
min="0"
max="100"
aria-labelledby="price-range-label"
>
<input
aria-label="Minimum price"
type="range"
min="0"
max="100"
ng-model="minimum"
/>
<input
aria-label="Maximum price"
type="range"
min="0"
max="100"
ng-model="maximum"
/>
</div>
</main>
</body>
</html>
Reference workflows
The workflow page covers controlled and multi-thumb ranges, disabled state,
right-to-left direction, and vertical orientation. Every thumb uses the same
absolute bounds so its native position remains accurate. Applications that
require ordered or non-crossing values enforce that policy in AngularTS state.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Range Slider 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="slider = { controlledStart: 0.3, controlledEnd: 0.7, rangeStart: 25, rangeEnd: 50, multipleOne: 10, multipleTwo: 20, multipleThree: 70, rtl: 75, verticalOne: 50, verticalTwo: 25 }"
data-example="slider-controlled slider-range slider-multiple slider-rtl slider-vertical"
>
<main class="slider-workflow-grid">
<section
class="slider-workflow-section"
aria-labelledby="slider-controlled-title"
>
<header>
<h2 id="slider-controlled-title">Temperature</h2>
<output>
{{ slider.controlledStart }}, {{ slider.controlledEnd }}
</output>
</header>
<div ng-range-slider min="0" max="1" aria-label="Temperature range">
<input
type="range"
min="0"
max="1"
step="0.1"
ng-model="slider.controlledStart"
aria-label="Minimum temperature"
/>
<input
type="range"
min="0"
max="1"
step="0.1"
ng-model="slider.controlledEnd"
aria-label="Maximum temperature"
/>
</div>
</section>
<section
class="slider-workflow-section"
aria-labelledby="slider-range-title"
>
<header>
<h2 id="slider-range-title">Range</h2>
<output>{{ slider.rangeStart }}–{{ slider.rangeEnd }}</output>
</header>
<div ng-range-slider min="0" max="100" aria-label="Price range">
<input
type="range"
min="0"
max="100"
step="5"
ng-model="slider.rangeStart"
aria-label="Minimum price"
/>
<input
type="range"
min="0"
max="100"
step="5"
ng-model="slider.rangeEnd"
aria-label="Maximum price"
/>
</div>
</section>
<section
class="slider-workflow-section"
aria-labelledby="slider-multiple-title"
>
<header>
<h2 id="slider-multiple-title">Multiple values</h2>
<output>
{{ slider.multipleOne }}, {{ slider.multipleTwo }}, {{
slider.multipleThree }}
</output>
</header>
<div
ng-range-slider
min="0"
max="100"
aria-label="Multiple slider values"
>
<input
type="range"
min="0"
max="100"
step="10"
ng-model="slider.multipleOne"
aria-label="First value"
/>
<input
type="range"
min="0"
max="100"
step="10"
ng-model="slider.multipleTwo"
aria-label="Second value"
/>
<input
type="range"
min="0"
max="100"
step="10"
ng-model="slider.multipleThree"
aria-label="Third value"
/>
</div>
</section>
<section
class="slider-workflow-section"
dir="rtl"
lang="ar"
aria-labelledby="slider-rtl-title"
>
<header>
<h2 id="slider-rtl-title">مستوى الصوت</h2>
<output>{{ slider.rtl }}</output>
</header>
<input
type="range"
min="0"
max="100"
step="1"
ng-model="slider.rtl"
aria-label="مستوى الصوت"
/>
</section>
<section
class="slider-workflow-section slider-workflow-wide"
aria-labelledby="slider-vertical-title"
>
<header>
<h2 id="slider-vertical-title">Vertical</h2>
<output> {{ slider.verticalOne }}, {{ slider.verticalTwo }} </output>
</header>
<div class="slider-vertical-row">
<input
type="range"
min="0"
max="100"
step="1"
orientation="vertical"
ng-model="slider.verticalOne"
aria-label="First vertical value"
/>
<input
type="range"
min="0"
max="100"
step="1"
orientation="vertical"
ng-model="slider.verticalTwo"
aria-label="Second vertical value"
/>
</div>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-range-slider]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Apply ng-range-slider to one container with two or more direct native input[type=range] children sharing the same minimum and maximum. Label every input independently. For one value, use a plain range input without an AngularCSS directive.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-orientation | Output | Interaction axis exposed to assistive technology. |
dir | Input | Text and interaction direction: ltr or rtl. |
max | Input | Maximum native or component value. |
min | Input | Minimum native or component value. |
orientation | Input/output | Layout direction: horizontal or vertical. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--range-end | Component styling variable. |
--range-start | Component styling variable. |
--value | Component styling variable. |
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
The directive coordinates two or more native range inputs on one shared track. It computes only composite geometry and ARIA orientation; each native input and its AngularTS ng-model retain value, focus, keyboard, validation, and form ownership. Use a plain range element when only one value is required.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Associate every control with a visible label. Preserve native required, disabled, and invalid semantics, and connect help or error text with aria-describedby.
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 [ng-range-slider], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.11 - resizable
Pointer- and keyboard-resizable split panels powered by --panel-size CSS variables.
Use ng-resizable-panel-group with alternating native section and hr
elements. Resize separators support pointer dragging and keyboard control.
<div ng-resizable-panel-group aria-label="Resizable layout">
<section style="--panel-size: 1">Preview</section>
<hr aria-label="Resize preview and details" />
<section>Details</section>
</div>
Set orientation="vertical" on the group to stack panels. Handles receive
separator roles, orientation, value bounds, current values, and aria-controls
relationships. Dragging or pressing Arrow, Home, and End keys updates adjacent
panel --panel-size values within data-min-size and data-max-size; RTL
reverses horizontal changes. CSS renders a visible grip without additional
markup.
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 Resizable</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="resizable-demo">
<div
ng-resizable-panel-group
orientation="horizontal"
aria-label="Resizable layout"
class="visual-example"
>
<section style="--panel-size: 1">
<div class="resizable-panel-content"><strong>One</strong></div>
</section>
<hr aria-label="Resize panel one and panels two and three" />
<section style="--panel-size: 1">
<div
ng-resizable-panel-group
orientation="vertical"
aria-label="Resize panels two and three"
>
<section style="--panel-size: 1">
<div class="resizable-panel-content"><strong>Two</strong></div>
</section>
<hr aria-label="Resize panel two and panel three" />
<section style="--panel-size: 3">
<div class="resizable-panel-content"><strong>Three</strong></div>
</section>
</div>
</section>
</div>
</body>
</html>
Orientations and RTL
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Resizable 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="resizable-handle resizable-rtl resizable-vertical"
>
<main class="resizable-workflows visual-example">
<section aria-label="Visible handle example">
<div
ng-resizable-panel-group
id="handle-layout"
orientation="horizontal"
aria-label="Sidebar and content layout"
class="resizable-reference-layout"
>
<section style="--panel-size: 1">
<div class="resizable-panel-content"><strong>Sidebar</strong></div>
</section>
<hr aria-label="Resize sidebar and content" />
<section style="--panel-size: 3">
<div class="resizable-panel-content"><strong>Content</strong></div>
</section>
</div>
</section>
<section aria-label="Vertical layout example">
<div
ng-resizable-panel-group
id="vertical-layout"
orientation="vertical"
data-step="0.5"
aria-label="Header and content layout"
class="resizable-reference-layout"
>
<section
data-min-size="0.5"
data-max-size="3.5"
style="--panel-size: 1"
>
<div class="resizable-panel-content"><strong>Header</strong></div>
</section>
<hr aria-label="Resize header and content" />
<section data-min-size="0.5" style="--panel-size: 3">
<div class="resizable-panel-content"><strong>Content</strong></div>
</section>
</div>
</section>
<section
class="resizable-workflow-wide"
aria-label="Right to left nested layout example"
lang="ar"
>
<div
ng-resizable-panel-group
id="rtl-layout"
orientation="horizontal"
aria-label="تخطيط قابل لتغيير الحجم"
class="resizable-reference-layout"
dir="rtl"
>
<section style="--panel-size: 1">
<div class="resizable-panel-content"><strong>واحد</strong></div>
</section>
<hr aria-label="تغيير حجم اللوحات" />
<section style="--panel-size: 1">
<div
ng-resizable-panel-group
orientation="vertical"
aria-label="تغيير حجم اللوحتين الثانية والثالثة"
dir="rtl"
>
<section style="--panel-size: 1">
<div class="resizable-panel-content">
<strong>اثنان</strong>
</div>
</section>
<hr aria-label="تغيير حجم اللوحتين الثانية والثالثة" />
<section style="--panel-size: 3">
<div class="resizable-panel-content">
<strong>ثلاثة</strong>
</div>
</section>
</div>
</section>
</div>
</section>
</main>
</body>
</html>
Reactive Structure
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Resizable State 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="resizableState={orientation:'horizontal',firstSize:1,showThird:false}"
>
<main class="resizable-state-workflows">
<section class="resizable-state-section" aria-labelledby="state-title">
<h2 id="state-title">Reactive layout</h2>
<div class="resizable-state-actions">
<button
size="sm"
type="button"
ng-click="resizableState.orientation=resizableState.orientation==='horizontal'?'vertical':'horizontal'"
>
Toggle orientation
</button>
<button size="sm" type="button" ng-click="resizableState.firstSize=2">
Set first size to 2
</button>
<button
size="sm"
type="button"
ng-click="resizableState.showThird=true"
>
Add third panel
</button>
</div>
<div
ng-resizable-panel-group
id="state-layout"
orientation="{{ resizableState.orientation }}"
data-step="0.25"
aria-label="Reactive resizable layout"
class="resizable-reference-layout"
>
<section
id="state-first-panel"
style="--panel-size: {{ resizableState.firstSize }}"
>
<div class="resizable-panel-content"><strong>One</strong></div>
</section>
<hr
id="state-first-handle"
aria-label="Resize first and second panels"
/>
<section style="--panel-size: 1">
<div class="resizable-panel-content"><strong>Two</strong></div>
</section>
<hr
ng-if="resizableState.showThird"
id="state-inserted-handle"
aria-label="Resize second and third panels"
/>
<section
ng-if="resizableState.showThird"
id="state-inserted-panel"
style="--panel-size: 1"
>
<div class="resizable-panel-content"><strong>Three</strong></div>
</section>
</div>
</section>
<section class="resizable-state-section" aria-labelledby="bounds-title">
<h2 id="bounds-title">Bounded vertical layout</h2>
<div
ng-resizable-panel-group
id="bounded-layout"
orientation="vertical"
data-step="0.5"
aria-label="Bounded vertical layout"
class="resizable-reference-layout"
>
<section
data-min-size="0.5"
data-max-size="2"
style="--panel-size: 1"
>
<div class="resizable-panel-content"><strong>Top</strong></div>
</section>
<hr aria-label="Resize bounded panels" />
<section data-min-size="0.5" style="--panel-size: 1">
<div class="resizable-panel-content"><strong>Bottom</strong></div>
</section>
</div>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-resizable-panel-group]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Alternate direct .resizable-panel and .resizable-handle children inside each panel group. The root directive inspects those children; no child directives are required. Nested groups belong inside a panel.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-controls | Output | ID of the element controlled by a trigger. |
aria-disabled | Input | Semantic disabled state. |
aria-orientation | Input/output | Interaction axis exposed to assistive technology. |
aria-valuemax | Output | Maximum value exposed by an adjustable control. |
aria-valuemin | Output | Minimum value exposed by an adjustable control. |
aria-valuenow | Output | Current value exposed by an adjustable control. |
data-max-size | Input | Largest panel flex size allowed during resizing. |
data-min-size | Input | Smallest panel flex size allowed during resizing. |
data-resizing | Output | Present while a pointer resize operation is active. |
data-step | Input | Panel flex-size increment used by keyboard resizing. |
dir | Input | Text and interaction direction: ltr or rtl. |
orientation | Input/output | Resize axis: horizontal or vertical. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
| Variable | Purpose |
|---|
--panel-size | Component styling variable. |
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
The directive owns pairwise pointer and keyboard resizing, minimum and maximum bounds, direct-child panel/handle ownership, direction-aware deltas, and synchronized separator state. AngularTS or the application owns authored orientation, initial/external sizes, structural insertion, persistence, and business layout decisions.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give each resize handle a concise accessible name. Handles expose separator semantics, the physical resize axis through aria-orientation, current and bounded values, and aria-controls relationships to both adjacent panels. Keyboard resizing follows text direction and preserves visible focus.
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 [ng-resizable-panel-group], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.12 - sidebar
Application sidebar layout with collapsible state
Use ng-sidebar on an aside inside .sidebar-layout and connect native
button triggers with aria-controls. Author physical side, visual variant, and
collapse mode directly on the sidebar root.
<div>
<aside id="app-sidebar" ng-sidebar side="left" collapsible="icon">
<header>
<a href="/">Acme Inc.</a>
</header>
<nav>
<section>
<h3>Workspace</h3>
<div>
<ul>
<li>
<a aria-current="page" href="/dashboard"> Dashboard </a>
</li>
</ul>
</div>
</section>
</nav>
</aside>
<main>
<button aria-controls="app-sidebar">Toggle sidebar</button>
</main>
</div>
The directive reads root options and coordinates collapse, group relationships,
and trigger accessibility state. AngularTS may control the boolean collapsed
attribute; it continues to own filtering, shortcuts, routing, and actions.
Compose nested disclosure with native details.disclosure and action menus
with ng-dropdown-menu. Add responsive to an off-canvas sidebar to initialize
it collapsed below 48rem and expanded at larger viewport widths.
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 Sidebar</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="sidebarOpen=true; sidebarQuery=''"
ng-keydown="($event.ctrlKey || $event.metaKey) && $event.key === 'b' && (sidebarOpen = !sidebarOpen)"
data-example="sidebar-demo sidebar-controlled"
>
<div class="visual-example">
<aside
id="app-sidebar"
ng-sidebar
collapsible="icon"
ng-attr-collapsed="{{ sidebarOpen ? undefined : '' }}"
class="sidebar-demo-panel"
aria-label="Workspace navigation"
>
<header>
<a href="#workspace" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">A</span>
<span class="sidebar-brand-copy">
<strong>Acme Inc</strong>
<small>Enterprise</small>
</span>
</a>
<input
ng-model="sidebarQuery"
aria-label="Filter navigation"
placeholder="Filter projects..."
/>
</header>
<hr />
<nav>
<section>
<h3>Platform</h3>
<ul>
<li>
<a href="#playground" aria-current="page">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
<path d="m8 9 2 2-2 2M13 15h3"></path>
</svg>
<span>Playground</span>
</a>
<ul>
<li>
<a href="#history">History</a>
</li>
<li>
<a href="#starred">Starred</a>
</li>
<li>
<a href="#settings">Settings</a>
</li>
</ul>
</li>
<li>
<a href="#models">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="8" r="3"></circle>
<path d="M5 20c1-4 3.5-6 7-6s6 2 7 6"></path>
</svg>
<span>Models</span>
</a>
</li>
<li>
<a href="#documentation">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path
d="M4 5.5A2.5 2.5 0 0 1 6.5 3H11v17H6.5A2.5 2.5 0 0 0 4 22zM20 5.5A2.5 2.5 0 0 0 17.5 3H13v17h4.5A2.5 2.5 0 0 1 20 22z"
></path>
</svg>
<span>Documentation</span>
</a>
</li>
</ul>
</section>
<section>
<h3>Projects</h3>
<ul>
<li>
<a href="#design">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Design Engineering</span>
</a>
<output>24</output>
</li>
<li>
<a href="#sales">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Sales & Marketing</span>
</a>
<output>12</output>
</li>
<li>
<a href="#travel">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Travel</span>
</a>
<output>3</output>
</li>
</ul>
</section>
</nav>
<footer>
<button size="lg">
<span class="avatar"><span>JD</span></span>
<span class="sidebar-brand-copy">
<strong>Jane Doe</strong>
<small>jane@example.com</small>
</span>
</button>
</footer>
</aside>
<main class="sidebar-demo-inset">
<header class="sidebar-demo-toolbar">
<button
variant="ghost"
size="sm"
aria-controls="app-sidebar"
aria-keyshortcuts="Control+B Meta+B"
ng-click="sidebarOpen=!sidebarOpen"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="4" width="18" height="16" rx="2"></rect>
<path d="M9 4v16"></path>
</svg>
<span
ng-bind="sidebarOpen ? 'Close Sidebar' : 'Open Sidebar'"
></span>
</button>
</header>
<section class="sidebar-dashboard">
<div>
<span class="sidebar-dashboard-kicker">Overview</span>
<h1>Dashboard</h1>
<p>Monitor your team activity and active projects.</p>
</div>
<div class="sidebar-metric-grid">
<article><span>Active projects</span><strong>24</strong></article>
<article><span>Team members</span><strong>18</strong></article>
<article><span>Completion</span><strong>86%</strong></article>
</div>
<output class="sidebar-query-output" aria-live="polite">
Filter: <span ng-bind="sidebarQuery || 'All projects'"></span>
</output>
</section>
</main>
</div>
</body>
</html>
Anatomy
Header and footer menus, labeled groups, actions, badges, submenus, and loading
rows remain independently composable.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar Anatomy</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="sidebarAction='None'; projectsLoading=true"
data-example="sidebar-footer sidebar-group sidebar-group-action sidebar-header sidebar-menu sidebar-menu-action sidebar-menu-badge sidebar-menu-sub sidebar-rsc"
>
<div class="sidebar-anatomy-shell visual-example">
<aside
id="anatomy-sidebar"
ng-sidebar
collapsible="none"
class="sidebar-anatomy-panel"
>
<header>
<div ng-dropdown-menu>
<button size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">A</span>
<span class="sidebar-brand-copy">
<strong>Select Workspace</strong>
<small>Acme Inc</small>
</span>
</button>
<menu>
<button ng-click="sidebarAction='Workspace: Acme Inc'">
Acme Inc
</button>
<button ng-click="sidebarAction='Workspace: Acme Corp.'">
Acme Corp.
</button>
</menu>
</div>
</header>
<nav>
<section>
<h3>Projects</h3>
<button
aria-label="Add Project"
ng-click="sidebarAction='Added project'"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M12 5v14M5 12h14"></path>
</svg>
</button>
<ul>
<li>
<a href="#design">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Design Engineering</span>
</a>
<div ng-dropdown-menu>
<button aria-label="More actions for Design Engineering">
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
>
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
</button>
<menu side="right" align="start">
<button
ng-click="sidebarAction='Edited Design Engineering'"
>
Edit Project
</button>
<button
ng-click="sidebarAction='Deleted Design Engineering'"
>
Delete Project
</button>
</menu>
</div>
</li>
<li>
<a href="#sales">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Sales & Marketing</span>
</a>
<output>12</output>
</li>
<li>
<a href="#travel">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Travel</span>
</a>
<output>3</output>
</li>
</ul>
</section>
<section>
<h3>Documentation</h3>
<ul>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
<li>
<a href="#installation">Installation</a>
</li>
<li>
<a aria-current="page" href="#structure"
>Project Structure</a
>
</li>
</ul>
</li>
</ul>
</section>
<section>
<h3>Remote projects</h3>
<button
aria-label="Toggle loading"
ng-click="projectsLoading=!projectsLoading"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M20 12a8 8 0 1 1-2.3-5.7M20 4v6h-6"></path>
</svg>
</button>
<ul>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li ng-if="!projectsLoading">
<a href="#support">Support</a>
</li>
<li ng-if="!projectsLoading">
<a href="#feedback">Feedback</a>
</li>
</ul>
</section>
</nav>
<footer>
<div ng-dropdown-menu>
<button size="lg">
<span class="avatar"><span>UN</span></span>
<span class="sidebar-brand-copy"
><strong>Username</strong><small>Account menu</small></span
>
</button>
<menu side="top">
<button ng-click="sidebarAction='Account'">Account</button>
<button ng-click="sidebarAction='Billing'">Billing</button>
<button ng-click="sidebarAction='Signed out'">Sign out</button>
</menu>
</div>
</footer>
</aside>
<main class="sidebar-anatomy-inset">
<div>
<span class="sidebar-dashboard-kicker">Component anatomy</span>
<h1>Sidebar primitives</h1>
<p>
Header, footer, groups, actions, badges, submenus, and loading
states compose independently.
</p>
</div>
<output
class="sidebar-anatomy-output"
aria-live="polite"
ng-bind="sidebarAction"
></output>
</main>
</div>
</body>
</html>
Disclosure Navigation
This example delegates both group and menu disclosure to the existing
Disclosure pattern.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar Collapsible</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="sidebar-group-collapsible sidebar-menu-collapsible"
>
<div class="sidebar-collapsible-shell visual-example">
<aside
id="collapsible-sidebar"
ng-sidebar
collapsible="none"
class="sidebar-collapsible-panel"
aria-label="Documentation navigation"
>
<header>
<a href="#docs" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">D</span>
<span class="sidebar-brand-copy">
<strong>Documentation</strong>
<small>Developer platform</small>
</span>
</a>
</header>
<nav>
<details open class="disclosure">
<summary>
Help
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#support">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="9"></circle>
<path
d="M8.5 8.5 6 6m9.5 2.5L18 6m-9.5 9.5L6 18m9.5-2.5L18 18"
></path>
</svg>
<span>Support</span>
</a>
</li>
<li>
<a href="#feedback">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m22 2-7 20-4-9-9-4zM22 2 11 13"></path>
</svg>
<span>Feedback</span>
</a>
</li>
</ul>
</div>
</details>
<section>
<h3>Guide</h3>
<ul>
<li>
<details open class="disclosure">
<summary>
<span>Getting Started</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#installation">Installation</a>
</li>
<li>
<a aria-current="page" href="#structure"
>Project Structure</a
>
</li>
</ul>
</div>
</details>
</li>
<li>
<details class="disclosure">
<summary>
<span>Build Your Application</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#routing">Routing</a>
</li>
<li>
<a href="#data">Data Fetching</a>
</li>
<li>
<a href="#rendering">Rendering</a>
</li>
</ul>
</div>
</details>
</li>
<li>
<details class="disclosure">
<summary>
<span>API Reference</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#components">Components</a>
</li>
<li>
<a href="#functions">Functions</a>
</li>
</ul>
</div>
</details>
</li>
</ul>
</section>
</nav>
</aside>
<main class="sidebar-collapsible-inset">
<span class="sidebar-dashboard-kicker">Composition</span>
<h1>Collapsible navigation</h1>
<p>Disclosure behavior is supplied by native details elements.</p>
</main>
</div>
</body>
</html>
RTL
Physical right placement and logical borders, actions, and submenu indentation
follow the authored document direction.
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 Sidebar 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="sidebarOpen=true; sidebarAction='جاهز'"
data-example="sidebar-rtl"
>
<div class="sidebar-rtl-shell visual-example">
<main class="sidebar-rtl-inset">
<header class="sidebar-demo-toolbar">
<button
variant="ghost"
size="sm"
aria-controls="rtl-sidebar"
ng-click="sidebarOpen=!sidebarOpen"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="4" width="18" height="16" rx="2"></rect>
<path d="M15 4v16"></path>
</svg>
<span ng-bind="sidebarOpen ? 'إغلاق الشريط' : 'فتح الشريط'"></span>
</button>
</header>
<section class="sidebar-dashboard">
<div>
<span class="sidebar-dashboard-kicker">نظرة عامة</span>
<h1>لوحة التحكم</h1>
<p>تابع نشاط الفريق والمشاريع الحالية.</p>
</div>
<output
class="sidebar-anatomy-output"
aria-live="polite"
ng-bind="sidebarAction"
></output>
</section>
</main>
<aside
id="rtl-sidebar"
ng-sidebar
side="right"
variant="floating"
collapsible="icon"
ng-attr-collapsed="{{ sidebarOpen ? undefined : '' }}"
class="sidebar-rtl-panel"
aria-label="التنقل في مساحة العمل"
>
<header>
<a href="#workspace" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">أ</span>
<span class="sidebar-brand-copy"
><strong>شركة أكمي</strong><small>المؤسسة</small></span
>
</a>
</header>
<nav>
<section>
<h3>المنصة</h3>
<ul>
<li>
<a aria-current="page" href="#playground">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
<path d="m8 9 2 2-2 2M13 15h3"></path>
</svg>
<span>ملعب</span>
</a>
<ul>
<li>
<a href="#history">السجل</a>
</li>
<li>
<a href="#starred">المميز</a>
</li>
<li>
<a href="#settings">الإعدادات</a>
</li>
</ul>
</li>
<li>
<a href="#models"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>النماذج</span></a
>
</li>
</ul>
</section>
<section>
<h3>المشاريع</h3>
<ul>
<li>
<a href="#design"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>هندسة التصميم</span></a
>
<div ng-dropdown-menu>
<button aria-label="المزيد">
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
>
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
</button>
<menu side="left" align="start">
<button ng-click="sidebarAction='عرض المشروع'">
عرض المشروع
</button>
<button ng-click="sidebarAction='مشاركة المشروع'">
مشاركة المشروع
</button>
</menu>
</div>
</li>
<li>
<a href="#sales"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>المبيعات والتسويق</span></a
>
</li>
<li>
<a href="#travel"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>السفر</span></a
>
</li>
</ul>
</section>
</nav>
<footer>
<button size="lg" ng-click="sidebarAction='الحساب'">
<span class="avatar"><span>ش</span></span>
<span class="sidebar-brand-copy"
><strong>أنغولار سي إس إس</strong
><small>team@angularcss.dev</small></span
>
</button>
</footer>
</aside>
</div>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-sidebar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Place aside[ng-sidebar] beside main and connect native button triggers with aria-controls. The root directive inspects semantic header, nav, section, list, and footer descendants; no child sidebar directives or anatomy classes are required. Author side, variant, and collapse mode on the root. Compose nested disclosure with native details.disclosure and action menus with ng-dropdown-menu.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-controls | Output | ID of the element controlled by a trigger. |
aria-current | Input | Current item or date state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
collapsed | Input/output | Current collapsed state. |
collapsible | Input/output | Collapse behavior: offcanvas, icon, or none. |
inert | Output | Prevents interaction while the component is hidden. |
responsive | Input | Collapses an off-canvas sidebar below 48rem and expands it above that breakpoint. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
side | Input/output | Physical placement: left or right. |
variant | Input/output | Surface style: sidebar, floating, or inset. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive reflects authored side, variant, collapsible, direction, responsive, active-item, group, and trigger state. It owns only sidebar collapse and accessibility synchronization; collapsible=none stays expanded, off-canvas collapse hides the landmark, and icon collapse keeps visible controls accessible. AngularTS remains responsible for controlled open state, shortcuts, filtering, routing, application actions, and structural rendering. Compose nested disclosure with the Disclosure pattern and action menus with Dropdown Menu.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the sidebar landmark and icon-only actions useful accessible names. Triggers expose aria-controls and expanded state, groups are associated with visible labels, and the current destination uses aria-current=page. Off-canvas collapse hides the landmark and restores trigger focus when necessary; icon collapse preserves access to its visible controls. Keep DOM order aligned with physical placement and use native links for destinations.
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 [ng-sidebar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.13 - tabs
Tabbed content sections
Add ng-tabs to a section, place native buttons in its list, and follow the
list with direct semantic section or article panels. The directive assigns
tab roles, relationships, selection state, and keyboard navigation.
<section ng-tabs>
<menu>
<button aria-selected="true">Overview</button>
</menu>
<section>Content</section>
</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 Tabs</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="tabs-demo">
<section ng-tabs>
<menu aria-label="Project sections">
<button aria-selected="true">Overview</button>
<button>Analytics</button>
<button>Reports</button>
<button>Settings</button>
</menu>
<article>
<header>
<h2>Overview</h2>
<p>
View your key metrics and recent project activity. Track progress
across all your active projects.
</p>
</header>
<section class="muted">
You have 12 active projects and 3 pending tasks.
</section>
</article>
<article>
<header>
<h2>Analytics</h2>
<p>
Track performance and user engagement metrics. Monitor trends and
identify growth opportunities.
</p>
</header>
<section class="muted">
Page views are up 25% compared to last month.
</section>
</article>
<article>
<header>
<h2>Reports</h2>
<p>
Generate and download your detailed reports. Export data in multiple
formats for analysis.
</p>
</header>
<section class="muted">
You have 5 reports ready and available to export.
</section>
</article>
<article>
<header>
<h2>Settings</h2>
<p>
Manage your account preferences and options. Customize your
experience to fit your needs.
</p>
</header>
<section class="muted">
Configure notifications, security, and themes.
</section>
</article>
</section>
</body>
</html>
Workflows
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Tabs 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="advancedVisible = false; overviewDisabled = false"
data-example="tabs-disabled tabs-icons tabs-line tabs-rtl tabs-vertical"
>
<main class="tabs-workflows visual-example">
<section aria-labelledby="tabs-dynamic-heading">
<header>
<h2 id="tabs-dynamic-heading">Dynamic sections</h2>
<button
type="button"
variant="outline"
size="sm"
ng-click="advancedVisible = !advancedVisible"
>
{{ advancedVisible ? 'Remove advanced' : 'Add advanced' }}
</button>
</header>
<section ng-tabs id="dynamic-tabs">
<menu aria-label="Dynamic project sections">
<button aria-selected="true">Overview</button>
<button>Activity</button>
<button ng-if="advancedVisible">Advanced</button>
</menu>
<section>Project overview</section>
<section>Recent project activity</section>
<section ng-if="advancedVisible">Advanced project controls</section>
</section>
</section>
<section aria-labelledby="tabs-disabled-heading">
<header>
<h2 id="tabs-disabled-heading">Disabled state</h2>
<button
type="button"
variant="outline"
size="sm"
ng-click="overviewDisabled = !overviewDisabled"
>
{{ overviewDisabled ? 'Enable overview' : 'Disable overview' }}
</button>
</header>
<section ng-tabs id="disabled-tabs">
<menu aria-label="Account sections">
<button aria-selected="true" ng-disabled="overviewDisabled">
Overview
</button>
<button>Settings</button>
<button disabled>Unavailable</button>
</menu>
<section>Account overview</section>
<section>Account settings</section>
<section>Unavailable settings</section>
</section>
</section>
<section aria-labelledby="tabs-vertical-heading">
<header><h2 id="tabs-vertical-heading">Vertical</h2></header>
<section ng-tabs orientation="vertical" id="vertical-tabs">
<menu aria-label="Preference sections">
<button aria-selected="true">Account</button>
<button>Password</button>
<button>Notifications</button>
</menu>
<section>Account preferences</section>
<section>Password preferences</section>
<section>Notification preferences</section>
</section>
</section>
<section aria-labelledby="tabs-variants-heading">
<header><h2 id="tabs-variants-heading">Variants</h2></header>
<div class="tabs-variant-stack">
<section ng-tabs id="icon-tabs">
<menu aria-label="Editor view">
<button aria-selected="true">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="4" width="18" height="16" rx="2" />
<path d="M3 9h18" />
</svg>
Preview
</button>
<button>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m8 9-3 3 3 3M16 9l3 3-3 3" />
</svg>
Code
</button>
</menu>
</section>
<section ng-tabs id="line-tabs">
<menu variant="line" aria-label="Report sections">
<button aria-selected="true">Overview</button>
<button>Analytics</button>
<button>Reports</button>
</menu>
</section>
</div>
</section>
<section aria-labelledby="tabs-rtl-heading" dir="rtl" lang="ar">
<header><h2 id="tabs-rtl-heading">الاتجاه من اليمين</h2></header>
<section ng-tabs id="rtl-tabs">
<menu aria-label="أقسام المشروع">
<button>نظرة عامة</button>
<button aria-selected="true">التحليلات</button>
<button>التقارير</button>
</menu>
<section>نظرة عامة على المشروع</section>
<section>تحليلات المشروع</section>
<section>تقارير المشروع</section>
</section>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-tabs]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Use native elements for authored structure. Component classes are optional visual hooks when an HTML relationship is not specific enough.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-controls | Output | ID of the element controlled by a trigger. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
aria-orientation | Input/output | Interaction axis exposed to assistive technology. |
aria-selected | Input/output | Selected item state. |
dir | Input | Text and interaction direction: ltr or rtl. |
orientation | Input/output | Layout direction: horizontal or vertical. |
role | Output | Explicit semantic role when native HTML does not provide one. |
tabindex | Output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive supplies navigation semantics and keyboard state where required. URLs, routing, current-page state, and navigation side effects remain application-owned.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use semantic navigation landmarks and links. Expose the current destination with aria-current and keep keyboard order consistent with visual 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 [ng-tabs], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.14 - toast
Notification toaster with close actions and toast variants.
Use ng-toast on the container; direct article children are toast items. Application
code owns toast creation and queueing. Set type or variant to success,
info, warning, error, or loading; the directive mirrors the result to
data-type for styling.
<div ng-toast>
<article type="success">
<article>
<article>Saved</article>
<article>Update published.</article>
</article>
</article>
</div>
Toast titles and descriptions are connected through aria-labelledby and
aria-describedby. Authored relationships are preserved. Toast action and close
buttons default to type="button", so they do not submit an enclosing form.
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 Toast</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="canonical = { visible: false, status: 'Ready' }"
data-example="toast-demo"
>
<main class="visual-example">
<button
type="button"
variant="outline"
ng-click="canonical.visible = true; canonical.status = 'Toast shown'"
>
Show Toast
</button>
<output class="output">{{ canonical.status }}</output>
</main>
<div ng-toast position="bottom-right" aria-label="Notifications">
<article ng-if="canonical.visible" animate>
<section>
<h3>Event has been created</h3>
<p>Sunday, December 03, 2023 at 9:00 AM</p>
</section>
<button
variant="outline"
size="sm"
ng-click="canonical.visible = false; canonical.status = 'Undo selected'"
>
Undo
</button>
</article>
</div>
</body>
</html>
Reference workflows
The workflow page exercises description, all six positions, notification types,
and the loading-to-success promise transition. Its controller is compiled from
TypeScript; AngularCSS does not own the application queue or asynchronous state.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Toast 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>
<script src="../../js/toast-demo.umd.js"></script>
</head>
<body
ng-app="toastDemo"
ng-controller="ToastDemoController as toast"
ng-cloak
data-example="toast-description toast-position toast-types"
>
<main class="toast-workflow-grid">
<section
class="toast-workflow-section"
aria-labelledby="toast-description-title"
>
<h2 id="toast-description-title">With description</h2>
<button
type="button"
variant="outline"
ng-click="toast.showDescription()"
>
Show Toast
</button>
<div class="toast-inline-preview">
<div ng-toast aria-label="Description notifications">
<article ng-if="toast.descriptionVisible" animate>
<section>
<h3>Event has been created</h3>
<p>Monday, January 3rd at 6:00pm</p>
</section>
<button
variant="ghost"
size="icon-sm"
aria-label="Dismiss description toast"
ng-click="toast.dismissDescription()"
>
<span></span>
</button>
</article>
</div>
</div>
<output class="output">{{ toast.descriptionStatus }}</output>
</section>
<section
class="toast-workflow-section toast-workflow-wide"
aria-labelledby="toast-position-title"
>
<h2 id="toast-position-title">Position</h2>
<div class="toast-button-grid" aria-label="Toast positions">
<button
type="button"
variant="outline"
ng-click="toast.showPosition('top-left')"
>
Top Left
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPosition('top-center')"
>
Top Center
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPosition('top-right')"
>
Top Right
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPosition('bottom-left')"
>
Bottom Left
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPosition('bottom-center')"
>
Bottom Center
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPosition('bottom-right')"
>
Bottom Right
</button>
</div>
<div class="toast-position-preview">
<div
ng-toast
position="{{ toast.position }}"
aria-label="Position notifications"
>
<article ng-if="toast.positionVisible" animate>
<section>
<h3>Event has been created</h3>
</section>
<button
variant="ghost"
size="icon-sm"
aria-label="Dismiss position toast"
ng-click="toast.dismissPosition()"
>
<span></span>
</button>
</article>
</div>
</div>
<output class="output">Position: {{ toast.position }}</output>
</section>
<section
class="toast-workflow-section toast-workflow-wide"
aria-labelledby="toast-types-title"
>
<h2 id="toast-types-title">Types</h2>
<div class="toast-button-grid" aria-label="Toast types">
<button
type="button"
variant="outline"
ng-click="toast.showType('default')"
>
Default
</button>
<button
type="button"
variant="outline"
ng-click="toast.showType('success')"
>
Success
</button>
<button
type="button"
variant="outline"
ng-click="toast.showType('info')"
>
Info
</button>
<button
type="button"
variant="outline"
ng-click="toast.showType('warning')"
>
Warning
</button>
<button
type="button"
variant="outline"
ng-click="toast.showType('error')"
>
Error
</button>
<button
type="button"
variant="outline"
ng-click="toast.showPromise()"
>
Promise
</button>
</div>
<div class="toast-inline-preview toast-types-preview">
<div ng-toast aria-label="Type notifications">
<article type="{{ toast.type }}" ng-if="toast.typeVisible" animate>
<figure ng-if="toast.type === 'success'"></figure>
<figure ng-if="toast.type === 'info'"></figure>
<figure ng-if="toast.type === 'warning'"></figure>
<figure ng-if="toast.type === 'error'"></figure>
<figure ng-if="toast.type === 'loading'"></figure>
<section>
<h3>{{ toast.typeMessage }}</h3>
</section>
<button
variant="ghost"
size="icon-sm"
aria-label="Dismiss type toast"
ng-click="toast.dismissType()"
>
<span></span>
</button>
</article>
</div>
</div>
<output class="output">Type: {{ toast.type }}</output>
</section>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-toast]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Use native elements for authored structure. Component classes are optional visual hooks when an HTML relationship is not specific enough.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-atomic | Input/output | Whether an assistive technology announces the entire updated region. |
aria-describedby | Input/output | ID of the element that supplies the accessible description. |
aria-label | Input/output | Accessible name when visible text is insufficient. |
aria-labelledby | Input/output | ID of the element that supplies the accessible name. |
aria-live | Input/output | Announcement priority for updates to a live region. |
position | Input/output | Viewport placement: top-left, top-center, top-right, bottom-left, bottom-center, or bottom-right. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
type | Input/output | Toast state: default, error, info, loading, success, or warning. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive exposes presentation and announcement state. The application decides when feedback appears, changes, or is removed.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use the appropriate live-region or status semantics for dynamic feedback. Decorative feedback must stay hidden from assistive technology.
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 [ng-toast], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.15 - toolbar
Keyboard-navigable groups of actions
Add ng-toolbar to a semantic action container. AngularCSS provides one tab
stop and arrow-key movement while native buttons, links, and AngularTS retain
activation and command ownership.
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 Toolbar</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="toolbar-demo">
<main class="visual-example">
<menu ng-toolbar aria-label="Document actions">
<button size="icon-sm" variant="ghost" aria-label="Undo">↶</button>
<button size="icon-sm" variant="ghost" aria-label="Redo" disabled>
↷
</button>
<hr />
<button size="sm" variant="ghost">Copy</button>
<button size="sm" variant="ghost">Archive</button>
<button size="sm" variant="ghost">Export</button>
</menu>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-toolbar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Apply ng-toolbar to a semantic menu or container with an accessible name. Use aria-orientation="vertical" for a vertical toolbar. Author direct native buttons or links and optional direct separators; no child directives or toolbar part classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-disabled | Input/output | Semantic disabled state. |
aria-label | Input | Accessible name when visible text is insufficient. |
aria-orientation | Input/output | Interaction axis exposed to assistive technology. |
dir | Input | Text and interaction direction: ltr or rtl. |
disabled | Input | Disables native or component interaction. |
hidden | Input | Native visibility state observed when finding available items. |
orientation | Input | Layout direction: horizontal or vertical. |
role | Output | Explicit semantic role when native HTML does not provide one. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
Toolbar owns one roving tab stop and direction-aware arrow, Home, and End navigation across direct native buttons and links. Native activation and AngularTS commands remain unchanged.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Give the toolbar an accessible name. Keep actions as native buttons or links, preserve visible focus, and avoid placing text inputs inside the roving-focus sequence.
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 [ng-toolbar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.16 - tooltip
Contextual hover and focus labels
Use a native trigger with short, non-interactive descriptive content. Content
can be held visible with the wrapper’s concise open attribute for controlled
examples.
<span ng-tooltip>
<button>Hover</button>
<span side="top">Add to library</span>
</span>
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 Tooltip</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="tooltip-demo">
<main class="visual-example">
<span ng-tooltip>
<button type="button" variant="outline">Hover</button>
<span side="top">Add to library</span>
</span>
</main>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-tooltip]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
One trigger and one plain-text content element are required. Prefer a native button or link trigger. Tooltip content is descriptive and non-interactive; use Popover when the floating content needs controls or focus.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-describedby | Output | ID of the element that supplies the accessible description. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
open | Input | Initial or controlled open state. |
role | Output | Explicit semantic role when native HTML does not provide one. |
side | Input/output | Physical placement: left, top, bottom, or right. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write 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
The directive owns immediate hover and focus disclosure, Escape closure, synchronized controlled open state, text direction, and physical side placement. Tooltip content is descriptive, non-interactive, and never receives focus. AngularTS remains responsible for application state and the trigger action.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
The trigger exposes aria-describedby while the content uses role="tooltip". Tooltips open from hover and keyboard focus, close on Escape, and must not contain interactive controls or essential information. Wrap a disabled button in a hoverable trigger only when its unavailable state needs explanation.
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 [ng-tooltip], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
7.17 - tree
Hierarchical navigation and selection
Add ng-tree to a nested native list. The root directive supplies the
hierarchical focus, expansion, selection, and typeahead behavior that HTML does
not provide by itself.
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 Tree</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="tree-demo">
<div class="visual-example">
<ul
ng-tree
aria-label="Organization"
ng-on-angularcss:tree-select="selectedNode=$event.detail.value"
>
<li data-value="operations" aria-expanded="true">
<span>Operations <small>12</small></span>
<ul>
<li data-value="fulfillment">
<span>Fulfillment <small>7</small></span>
</li>
<li data-value="support">
<span>Support <small>5</small></span>
</li>
</ul>
</li>
<li data-value="finance" aria-expanded="false">
<span>Finance <small>8</small></span>
<ul>
<li data-value="accounts"><span>Accounts</span></li>
<li data-value="payroll"><span>Payroll</span></li>
</ul>
</li>
<li data-value="legal" aria-disabled="true">
<span>Legal <small>Restricted</small></span>
</li>
</ul>
<output aria-live="polite">Selected: {{ selectedNode || 'none' }}</output>
</div>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-tree]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
Semantic structure
Apply ng-tree to a native ul or ol. Each direct or nested li contains one direct text span followed by an optional nested list; no child directives or tree part classes are required.
API
Attributes and state
| Attribute | Access | Purpose |
|---|
aria-disabled | Input/output | Semantic disabled state. |
aria-expanded | Input/output | Open or expanded state exposed to assistive technology. |
aria-label | Input | Accessible name when visible text is insufficient. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
aria-multiselectable | Input | Set to true to allow Ctrl or Command click selection of several items. |
aria-selected | Input/output | Selected item state. |
data-value | Input | Application value included in angularcss:tree-select. |
disabled | Input | Disables native or component interaction. |
hidden | Input | Native visibility state observed when finding available items. |
role | Output | Explicit semantic role when native HTML does not provide one. |
tabindex | Input/output | Keyboard focus order for composite descendants. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write component-specific CSS custom properties.
DOM events
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
Tree owns hierarchical roving focus, expansion, typeahead, selection state, and selection signaling. AngularTS owns node data, rendering, permissions, lazy loading, and the selected application record.
AngularCSS does not replace AngularTS interpolation, bindings, structural
directives, form controllers, validation, or application state.
Accessibility
Use nested native lists with one direct text span per item. The directive supplies tree, group, and treeitem semantics, expanded and selected state, roving focus, arrow navigation, Home, End, and typeahead.
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 [ng-tree], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state
variants, and iframe demo isolation.
8 - Package Reference
Public AngularCSS package exports, module registration, distribution files, and component contracts.
The package root exposes AngularCSS registration state and automatically
registers all canonical directives when AngularTS is available.
import {
type AngularCssCustomEvent,
type AngularCssEventDetailMap,
angular,
angularCssDirectives,
angularCssModuleName,
registerAngularCss,
} from "@angular-wave/angular.css";
angularCssModuleName
The AngularTS module name registered by AngularCSS. Add it as an application
module dependency:
angular.createModule("app", [angularCssModuleName]);
angular
- Type: AngularTS runtime or
undefined
The AngularTS singleton found on the global scope when AngularCSS initializes.
Import AngularTS before AngularCSS in an ESM entrypoint. Most applications
should import their runtime directly from @angular-wave/angular.ts instead of
using this optional reference.
angularCssDirectives
- Type: array of directive registration tuples
The canonical directive registry. Each tuple contains the AngularTS directive
name and its factory. The list is public for integration diagnostics and custom
bootstrap tooling; applications normally consume it through the angular.css module.
registerAngularCss()
function registerAngularCss(
angular?: typeof angularRuntime,
): ng.NgModule | undefined;
Registers all canonical directives on the angular.css AngularTS module. It
returns the module when an AngularTS runtime is available and undefined
otherwise. Registration is idempotent for each runtime and reuses an existing
module instead of replacing it. The package calls this function automatically
on import.
Call it explicitly only when AngularTS is loaded after AngularCSS or when an
integration supplies a runtime instance manually.
Typed DOM events
The root export includes AngularCssEventName, AngularCssEventDetailMap,
AngularCssCustomEvent, and the detail interface for every component event.
It also augments HTMLElementEventMap, so TypeScript infers event details from
ordinary DOM listeners:
calendar.addEventListener("angularcss:calendar-select", (event) => {
console.log(event.detail.value, event.detail.selectionMode);
});
Distribution files
| File | Purpose |
|---|
dist/angular-css.esm.js | ESM entrypoint for bundlers. |
dist/angular-css.umd.js | Local browser script build. |
dist/angular.css | Compiled component and token stylesheet. |
@types/index.d.ts | Root TypeScript declarations. |
Component APIs
Use the component catalog for the public
HTML contract of every directive. Those pages are generated from canonical
TypeScript and document selectors, parts, attributes, state, CSS variables,
events, behavior, accessibility, and customization.
9 - Recipes
Opinionated compositions assembled from elements, patterns, and components.
9.1 - alert-dialog
Confirmation dialog structure
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.
9.2 - application-shell
Enterprise application header, navigation, and workspace
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
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.
9.3 - data-table
Sortable and filterable semantic table composition
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
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.
9.4 - date-picker
Calendar and native popover composition
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
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.
9.5 - drawer
Bottom anchored drawer panels
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
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.
9.6 - form-layout
Responsive enterprise form composition
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
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.
9.7 - master-detail
Resizable record list and detail workspace
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
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.
9.8 - sheet
Edge anchored overlay panels
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
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.