This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

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

  1. Introduction explains what AngularCSS owns and what remains native HTML or AngularTS behavior.
  2. Installation adds the local npm packages, stylesheet, and angular.css module.
  3. Build your first component creates an interactive accordion.
  4. 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:

  1. Introduction
  2. Installation
  3. First component
  4. Customization
  5. 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

  1. HTML owns semantics. Use button, input, dialog, nav, table, and other native elements whenever they fit the interaction.
  2. AngularTS owns application state. Use ng-model, ng-click, validation, interpolation, and structural directives for values and business behavior.
  3. 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

  1. Press Tab until the accordion trigger receives focus.
  2. Press Enter or Space to open and close the panel.
  3. Enter a display name and confirm the preview updates.
  4. 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.

Customization token format

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 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.

Tailwind and other CSS tools

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">-&gt;</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">-&gt;</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

  • [dir]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
alignAuthoredLogical text alignment: start or end.
dirAuthoredNative 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:

  1. AngularTS ownership
  2. Composition
  3. Accessibility
  4. 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.

Native HTML owns platform behavior

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.

Form field

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.

Disclosure sidebar group

Place native details.disclosure inside a sidebar group. Sidebar owns its global expanded state and responsive hooks; the browser owns nested disclosure.

Composition rules

  1. Assign each state value to one owner.
  2. Preserve semantic elements and authored labels.
  3. Reuse an existing primitive for focus or disclosure behavior.
  4. Connect composed regions with stable IDs and ARIA relationships.
  5. 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:

  1. Complete the workflow using only a keyboard.
  2. Confirm focus is always visible and restored after overlays close.
  3. Inspect the accessibility tree for names, roles, values, and relationships.
  4. Test validation and dynamic feedback with a screen reader.
  5. 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

npm run check

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

  • button

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-disabledAuthoredSemantic disabled state.
aria-haspopupAuthoredType of popup controlled by the trigger.
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
iconAuthoredIcon position: inline-start or inline-end.
sizeAuthoredSize: xs, sm, default, lg, icon-xs, icon-sm, icon, or icon-lg.
variantAuthoredStyle: 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

AttributeAccessPurpose
checkedAuthoredInitial native checked state.
disabledAuthoredDisables native or component interaction.
requiredAuthoredMarks 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>

Scrolling

Use a section directly inside the native dialog or its form for scrollable content, and add class="scroll-area" for native overflow. Keep the footer outside that section when its actions must remain visible.

View source
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Dialog Scroll Workflows</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body
    ng-app="angular.css"
    ng-cloak
    data-example="dialog-scrollable-content dialog-sticky-footer"
  >
    <main class="dialog-workflow-grid visual-example">
      <section class="dialog-workflow" aria-labelledby="scroll-heading">
        <h2 id="scroll-heading">Scrollable content</h2>
        <div id="scroll-dialog" class="dialog">
          <button
            variant="outline"
            type="button"
            commandfor="scroll-dialog-content"
            command="show-modal"
          >
            Read profile
          </button>
          <dialog
            size="wide"
            id="scroll-dialog-content"
            closedby="any"
            aria-labelledby="scroll-dialog-title"
            aria-describedby="scroll-dialog-description"
          >
            <header>
              <h3 id="scroll-dialog-title">About Pedro Duarte</h3>
              <p id="scroll-dialog-description">
                A short professional biography.
              </p>
            </header>
            <section class="dialog-prose">
              <p>
                Pedro is a designer and developer focused on accessible design
                systems and thoughtful product interfaces.
              </p>
              <p>
                He works across interaction design, component architecture, and
                documentation to make complex systems easier to use.
              </p>
              <p>
                His projects explore how strong defaults and composable APIs can
                support teams without limiting their visual language.
              </p>
              <p>
                Outside product work, he studies typography, browser behavior,
                and the details that make keyboard workflows feel dependable.
              </p>
              <p>
                He has collaborated with distributed teams building tools for
                creators, engineers, and operations specialists.
              </p>
              <p>
                This final paragraph ensures the body has genuine overflow and
                remains independently scrollable inside the viewport.
              </p>
            </section>
            <button
              variant="ghost"
              size="icon-sm"
              commandfor="scroll-dialog-content"
              command="close"
            >
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                aria-hidden="true"
              >
                <path d="M18 6 6 18"></path>
                <path d="m6 6 12 12"></path>
              </svg>
              <span class="visually-hidden">Close</span>
            </button>
          </dialog>
        </div>
      </section>

      <section class="dialog-workflow" aria-labelledby="sticky-heading">
        <h2 id="sticky-heading">Sticky footer</h2>
        <div id="sticky-dialog" class="dialog">
          <button
            variant="outline"
            type="button"
            commandfor="sticky-dialog-content"
            command="show-modal"
          >
            Review notes
          </button>
          <dialog
            size="wide"
            id="sticky-dialog-content"
            closedby="any"
            aria-labelledby="sticky-dialog-title"
            aria-describedby="sticky-dialog-description"
          >
            <header>
              <h3 id="sticky-dialog-title">Release notes</h3>
              <p id="sticky-dialog-description">
                Review the changes included in this release.
              </p>
            </header>
            <section class="dialog-prose">
              <p>
                Focus is now contained inside modal dialogs while they are open.
              </p>
              <p>
                Background content becomes inert and document scrolling is
                restored when the dialog closes.
              </p>
              <p>
                Internal triggers receive generated relationships to their
                directly owned dialog content.
              </p>
              <p>
                Nested overlays no longer acquire controls belonging to a child
                overlay root.
              </p>
              <p>
                Scrollable bodies retain the header and footer in stable
                positions throughout keyboard and pointer interaction.
              </p>
              <p>
                Logical positioning keeps the corner close control aligned in
                both left-to-right and right-to-left layouts.
              </p>
            </section>
            <footer>
              <button
                variant="outline"
                commandfor="sticky-dialog-content"
                command="close"
              >
                Cancel
              </button>
              <button commandfor="sticky-dialog-content" command="close">
                Confirm
              </button>
            </footer>
          </dialog>
        </div>
      </section>
    </main>
  </body>
</html>

Right To Left

View source
<!doctype html>
<html lang="ar" dir="rtl">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>AngularCSS Dialog Rtl</title>
    <link rel="stylesheet" href="../../css/preflight.css" />
    <link rel="stylesheet" href="../../css/angular.css" />
    <link rel="stylesheet" href="../example.css" />
    <script src="../../js/angular-ts.umd.js"></script>
    <script src="../../js/angular-css.umd.js"></script>
  </head>
  <body
    ng-app="angular.css"
    ng-cloak
    ng-init="profile={name:'محمد علي',username:'@mohamed'}"
    data-example="dialog-rtl"
  >
    <main class="visual-example">
      <section id="rtl-profile-dialog" class="dialog">
        <button
          variant="outline"
          type="button"
          commandfor="rtl-profile-dialog-content"
          command="show-modal"
        >
          تعديل الملف الشخصي
        </button>
        <dialog
          id="rtl-profile-dialog-content"
          closedby="any"
          aria-labelledby="rtl-profile-dialog-title"
          aria-describedby="rtl-profile-dialog-description"
        >
          <header>
            <h2 id="rtl-profile-dialog-title">تعديل الملف الشخصي</h2>
            <p id="rtl-profile-dialog-description">
              غيّر بيانات ملفك الشخصي ثم احفظ التعديلات.
            </p>
          </header>
          <section>
            <label for="rtl-name">
              <span>الاسم</span>
              <input id="rtl-name" ng-model="profile.name" />
            </label>
            <label for="rtl-username">
              <span>اسم المستخدم</span>
              <input id="rtl-username" ng-model="profile.username" />
            </label>
          </section>
          <footer>
            <button
              variant="outline"
              commandfor="rtl-profile-dialog-content"
              command="close"
            >
              إلغاء
            </button>
            <button commandfor="rtl-profile-dialog-content" command="close">
              حفظ التغييرات
            </button>
          </footer>
          <button
            variant="ghost"
            size="icon-sm"
            commandfor="rtl-profile-dialog-content"
            command="close"
          >
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              aria-hidden="true"
            >
              <path d="M18 6 6 18"></path>
              <path d="m6 6 12 12"></path>
            </svg>
            <span class="visually-hidden">إغلاق</span>
          </button>
        </dialog>
      </section>
    </main>
  </body>
</html>

Installation

Load the AngularCSS stylesheet. This entry needs no AngularCSS JavaScript or angular.css module dependency. Add AngularTS when using application bindings such as ng-model or ng-click. See Installation for the complete setup.

This entry uses native HTML and CSS. AngularCSS registers no runtime directive for it. Native dialog top-layer and modal behavior.

Anatomy

Root styling selector

  • .dialog

Semantic structure

Use .dialog as a composition wrapper containing a native invoker button and dialog. Close controls use command=close; semantic headers, sections, forms, and footers need no anatomy classes or nested AngularCSS attributes.

API

Attributes and state

AttributeAccessPurpose
closedbyAuthoredNative dialog dismissal behavior.
commandAuthoredNative invoker action such as show-modal or close.
commandforAuthoredID of the native dialog controlled by an invoker.
dirAuthoredText and interaction direction: ltr or rtl.
sizeAuthoredDialog 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

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
disabledAuthoredDisables native or component interaction.
sizeAuthoredNative number of visible characters; also enables content sizing when supported.
typeAuthoredNative 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

  • kbd

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

  • label

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
forAuthoredID 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

  • progress

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

AttributeAccessPurpose
dirAuthoredText and interaction direction: ltr or rtl.
maxAuthoredMaximum native or component value.
valueAuthoredNative 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 &amp; 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

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
checkedAuthoredInitial native checked state.
dirAuthoredText and interaction direction: ltr or rtl.
disabledAuthoredDisables native or component interaction.
nameAuthoredAuthored HTML attribute or styling hook.
requiredAuthoredMarks a native form value as required.
valueAuthoredNative 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

  • input[type="range"]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
disabledAuthoredDisables native or component interaction.
maxAuthoredMaximum native or component value.
minAuthoredMinimum native or component value.
orientationAuthoredLayout direction: horizontal or vertical.
stepAuthoredNative numeric step interval.
valueAuthoredNative 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

  • .scroll-area

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
dirAuthoredText and interaction direction: ltr or rtl.
tabindexAuthoredUse 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

  • select

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

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
dirAuthoredText and interaction direction: ltr or rtl.
disabledAuthoredDisables native or component interaction.
multipleAuthoredAllows more than one item to remain selected or open.
nameAuthoredAuthored HTML attribute or styling hook.
requiredAuthoredMarks a native form value as required.
sizeAuthoredVisual 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 &amp; security</span></div>
        <hr aria-orientation="vertical" />
        <div><strong>Help</strong><span>Support &amp; 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

  • hr

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-orientationAuthoredSeparator 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

AttributeAccessPurpose
checkedAuthoredInitial native checked state.
disabledAuthoredDisables native or component interaction.
requiredAuthoredMarks a native form value as required.
roleAuthoredExplicit semantic role when native HTML does not provide one.
sizeAuthoredSwitch 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

  • table

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-selectedAuthoredSelected 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

  • textarea

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
disabledAuthoredDisables native or component interaction.
requiredAuthoredMarks 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 &amp; Security</summary>
            <div>
              Enable two-factor authentication, review active sessions, and
              configure data sharing.
            </div>
          </details>
          <details>
            <summary>Billing &amp; 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 &amp; 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

AttributeAccessPurpose
inertAuthoredPrevents interaction while the component is hidden.
nameAuthoredAuthored HTML attribute or styling hook.
openAuthoredInitial 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

  • [role="alert"]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-atomicAuthoredWhether an assistive technology announces the entire updated region.
aria-liveAuthoredAnnouncement priority for updates to a live region.
roleAuthoredExplicit semantic role when native HTML does not provide one.
variantAuthoredStatus 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

  • figure[ratio]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
ratioAuthoredAspect 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

VariablePurpose
--ratioRendered 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

  • .avatar

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

AttributeAccessPurpose
sizeAuthoredAvatar size: sm or lg; omit for the default size.
variantAuthoredOptional 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

  • .badge

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
iconAuthoredDirect icon position: inline-start or inline-end.
variantAuthoredPresentation: 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

  • .breadcrumb

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-currentAuthoredCurrent item or date state.
dirAuthoredText 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

  • [role="group"]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-orientationAuthoredUse vertical on a direct separator when it divides controls along the inline axis.
orientationAuthoredGroup layout: vertical; omit for the horizontal layout.
roleAuthoredExplicit 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

  • .card

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
sizeAuthoredUse 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

VariablePurpose
--card-padding-blockBlock 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>

Axis, grid, tooltip, and legend

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>

Interactive, RTL, and tooltip 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 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

  • .chart

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

AttributeAccessPurpose
data-colorAuthoredSeries color key used by the example or application to set --chart-color.
data-valueAuthoredAuthored bar height as a percentage when --value is not set.
indicatorAuthoredLegend 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

VariablePurpose
--chart-colorColor for an authored series, mark, or legend indicator.
--valueBar 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

AttributeAccessPurpose
orientationAuthoredRow 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

  • .disclosure

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

AttributeAccessPurpose
openAuthoredInitial 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

  • .empty

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
variantAuthoredOptional 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 &amp; 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

  • .field

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
orientationAuthoredField layout: horizontal or responsive; omit for the vertical layout.
variantAuthoredCompact 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

AttributeAccessPurpose
acceptAuthoredNative accepted file types on the direct file input.
draggingAuthoredPresentational drop-target state on the root section.
multipleAuthoredAllows 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

AttributeAccessPurpose
roleAuthoredExplicit 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

  • .input-group

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

AttributeAccessPurpose
alignAuthoredDirect addon placement: inline-start, inline-end, block-start, or block-end.
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
borderAuthoredUse true on a direct block addon to draw its dividing border.
sizeAuthoredDirect 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

AttributeAccessPurpose
aria-invalidAuthoredValidation state exposed to assistive technology and CSS.
groupAuthoredOptional visual grouping size. Use 3 to separate a six-character code into two groups.
maxlengthAuthoredMaximum native text length.
patternAuthoredNative regular-expression validation constraint.
sizeAuthoredNative 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

VariablePurpose
--otp-cell-sizeWidth 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

  • .item

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
sizeAuthoredItem density: xs or sm; omit for the default size.
variantAuthoredItem 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

  • .pagination

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

AttributeAccessPurpose
aria-currentAuthoredCurrent item or date state.
aria-disabledAuthoredSemantic disabled state.
dirAuthoredText and interaction direction: ltr or rtl.
relAuthoredUse 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

AttributeAccessPurpose
alignAuthoredPopover alignment: start, center, or end.
popoverAuthoredNative Popover API state and behavior on the surface.
popovertargetAuthoredID of the sibling popover controlled by the trigger.
sideAuthoredPreferred 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

  • .skeleton

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

  • .spinner

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
sizeAuthoredSpinner 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

AttributeAccessPurpose
aria-currentAuthoredCurrent 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

  • button[aria-pressed]

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
aria-disabledAuthoredSemantic disabled state.
aria-pressedAuthoredPressed state of a toggle control.
sizeAuthoredToggle size: sm or lg; omit for the default size.
variantAuthoredToggle 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

  • .toggle-group

Semantic structure

Use semantic HTML with the root styling selector above. Native elements provide the structure; the stylesheet supplies presentation.

API

Attributes and state

AttributeAccessPurpose
orientationAuthoredGroup layout: vertical; omit for the horizontal layout.
sizeAuthoredControl size: sm or lg; omit for the default size.
spacingAuthoredGap in spacing units: 1 or 2; omit to join controls.
variantAuthoredControl 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

VariablePurpose
--toggle-group-gapGap 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

AttributeAccessPurpose
roleAuthoredExplicit semantic role when native HTML does not provide one.
tabindexAuthoredKeyboard 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:

  1. What the component does and where to use it.
  2. What semantic HTML and directive selectors it requires.
  3. Which parts, attributes, state hooks, CSS variables, and events it exposes.
  4. Which behavior belongs to AngularCSS, AngularTS, native HTML, or application code.
  5. What accessibility and customization constraints apply.

Action

Command Palette

Date Input

Feedback

Form

Form Overlay

Layout

Media

Menu

Navigation

Overlay

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

  • ng-calendar

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

AttributeAccessPurpose
aria-currentInput/outputCurrent item or date state.
aria-disabledOutputSemantic disabled state.
aria-labelInput/outputAccessible name when visible text is insufficient.
aria-labelledbyOutputID of the element that supplies the accessible name.
aria-liveOutputAnnouncement priority for updates to a live region.
aria-pressedInput/outputPressed state of a toggle control.
data-bookedOutputWhether a generated calendar day is booked.
data-booked-datesInputComma-separated ISO dates styled as booked.
data-calendar-generatedInputEnables generated month markup inside the authored Calendar shell.
data-calendar-presetInputGenerated calendar preset: single, multiple, or range.
data-caption-layoutInputCaption controls: label or dropdown.
data-columnsInputNumber of columns used for calendar grid keyboard movement; defaults to 7.
data-disabled-afterInputLast selectable date as an ISO date.
data-disabled-beforeInputFirst selectable date as an ISO date.
data-disabled-datesInputComma-separated ISO dates that cannot be selected.
data-end-yearInputFinal year offered by a dropdown caption.
data-min-nightsInputMinimum number of nights accepted by range selection.
data-monthInput/outputDisplayed month in YYYY-MM form.
data-monthsOutputNumber of month grids currently rendered.
data-number-of-monthsInputNumber of consecutive months to render.
data-outsideInput/outputWhether a day belongs to an adjacent month.
data-range-endOutputMarks the final day in the selected range.
data-range-end-valueInput/outputSelected range end as an ISO date.
data-range-invalidOutputWhether the pending range violates the minimum-night constraint.
data-range-middleOutputMarks a day between the selected range boundaries.
data-range-startOutputMarks the first day in the selected range.
data-range-start-valueInput/outputSelected range start as an ISO date.
data-selection-modeInputSelection behavior: single, multiple, or range.
data-show-outside-daysInputShows dates from adjacent months when true.
data-show-week-numbersInput/outputShows ISO-style week numbers when true.
data-start-yearInputFirst year offered by a dropdown caption.
data-valueInput/outputSelected ISO date for single selection.
data-valuesInput/outputComma-separated selected ISO dates for multiple selection.
data-week-startInputFirst weekday as an integer from 0 (Sunday) to 6 (Saturday).
dirInputText and interaction direction: ltr or rtl.
langInputLanguage used for generated labels and localized text.
selectedOutputSelected value reflected by the component.
tabindexInput/outputKeyboard focus order for composite descendants.
valueOutputNative 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

VariablePurpose
--calendar-cell-sizeWidth and height of calendar controls and day cells.

DOM events

  • angularcss:calendar-month-change
  • angularcss:calendar-range-invalid
  • angularcss: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

  • ng-carousel

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

AttributeAccessPurpose
alignInputCross-axis alignment: start, center, or end.
aria-currentOutputCurrent item or date state.
aria-disabledOutputSemantic disabled state.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelInput/outputAccessible name when visible text is insufficient.
aria-roledescriptionOutputHuman-readable description of the component role.
autoplayInputEnables the locally bundled Embla autoplay plugin.
autoplay-delayInputAutoplay delay in milliseconds.
contain-scrollInputEmbla scroll containment mode.
dirInputText and interaction direction: ltr or rtl.
drag-freeInputAllows free dragging between snap points.
draggableInputSet to false to disable pointer dragging.
loopInputAllows navigation to wrap from the final item to the first.
orientationInput/outputLayout direction: horizontal or vertical.
roleInput/outputExplicit semantic role when native HTML does not provide one.
skip-snapsInputAllows momentum to skip snap points.
slides-to-scrollInputNumber of slides advanced as one snap group.
tabindexInput/outputKeyboard 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

VariablePurpose
--carousel-gapGap between slides; defaults to four spacing units.
--carousel-item-sizeSlide basis; defaults to 100%.

DOM events

  • angularcss:carousel-change
  • angularcss: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

  • ng-combobox

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

AttributeAccessPurpose
aria-activedescendantOutputID of the active option while focus remains on the composite control.
aria-autocompleteInput/outputHow a text control presents completion suggestions.
aria-controlsOutputID of the element controlled by a trigger.
aria-disabledInput/outputSemantic disabled state.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-haspopupOutputType of popup controlled by the trigger.
aria-hiddenInput/outputWhether generated or collapsed content is hidden from assistive technology.
aria-invalidInputValidation state exposed to assistive technology and CSS.
aria-labelInput/outputAccessible name when visible text is insufficient.
aria-labelledbyOutputID of the element that supplies the accessible name.
aria-multiselectableOutputWhether the composite allows multiple selected items.
aria-orientationOutputInteraction axis exposed to assistive technology.
aria-selectedInput/outputSelected item state.
auto-highlightInputHighlights the first enabled result when the popup opens or filters change.
data-highlightedOutputCurrent option highlighted for keyboard selection.
data-valueInputApplication value reported when the corresponding option is selected.
dirInputText and interaction direction: ltr or rtl.
disabledInputDisables native or component interaction.
hiddenInputNative visibility state observed when finding available items.
multipleInputKeeps the popup open and reports selections for an application-owned collection.
openInput/outputInitial or externally synchronized disclosure state.
requiredInputMarks a native form value as required.
roleOutputExplicit semantic role when native HTML does not provide one.
sideOutputPhysical placement: left, top, bottom, or right.
tabindexOutputKeyboard 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

VariablePurpose
--combobox-anchor-widthComponent styling variable.
--combobox-content-topComponent styling variable.

DOM events

  • angularcss:combobox-clear
  • angularcss:combobox-open-change
  • angularcss:combobox-remove-last
  • angularcss: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>

Scrollable

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

  • ng-command

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

AttributeAccessPurpose
aria-activedescendantOutputID of the active option while focus remains on the composite control.
aria-autocompleteInput/outputHow a text control presents completion suggestions.
aria-controlsOutputID of the element controlled by a trigger.
aria-disabledInput/outputSemantic disabled state.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-hiddenInput/outputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
aria-orientationOutputInteraction axis exposed to assistive technology.
aria-selectedInput/outputSelected item state.
dirInputText and interaction direction: ltr or rtl.
disabledInputDisables native or component interaction.
hiddenInputNative visibility state observed when finding available items.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexOutputKeyboard 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

  • ng-context-menu

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

AttributeAccessPurpose
alignInput/outputCross-axis alignment: start, center, or end.
align-offsetInputAdditional alignment offset in CSS pixels.
aria-checkedInput/outputARIA relationship or state.
aria-controlsOutputID of the element controlled by a trigger.
aria-disabledInput/outputSemantic disabled state.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-haspopupOutputType of popup controlled by the trigger.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
dirInputText and interaction direction: ltr or rtl.
disabledInputDisables native or component interaction.
openInputInitial or controlled open state.
roleOutputExplicit semantic role when native HTML does not provide one.
sideInput/outputPhysical placement: left, top, bottom, or right.
side-offsetInputDistance from the invocation point in CSS pixels.
tabindexInput/outputKeyboard 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

VariablePurpose
--context-menu-available-heightComponent styling variable.
--context-menu-leftComponent styling variable.
--context-menu-topComponent 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

  • ng-dropdown-menu

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

AttributeAccessPurpose
alignInputCross-axis alignment: start, center, or end.
align-offsetInputAdditional alignment offset in CSS pixels.
aria-checkedInput/outputARIA relationship or state.
aria-controlsOutputID of the element controlled by a trigger.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-haspopupInput/outputType of popup controlled by the trigger.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
dirInputText and interaction direction: ltr or rtl.
openInputInitial or controlled open state.
roleInput/outputExplicit semantic role when native HTML does not provide one.
sideInputPhysical placement: left, top, bottom, or right.
side-offsetInputDistance from the trigger in CSS pixels.
sizeInputVisual size token supported by the component stylesheet.
tabindexInput/outputKeyboard 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

VariablePurpose
--dropdown-menu-available-heightComponent 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

  • ng-hover-card

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

AttributeAccessPurpose
aria-controlsOutputID of the element controlled by a trigger.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
close-delayInputPointer close delay in milliseconds.
openInputInitial or controlled open state.
open-delayInputPointer open delay in milliseconds.
sideInput/outputPhysical 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 menus
  • Enter/Space/ArrowDown to open a menu
  • Escape to close menus
  • Home/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

  • ng-menubar

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

AttributeAccessPurpose
aria-checkedInput/outputARIA relationship or state.
aria-controlsOutputID of the element controlled by a trigger.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-haspopupOutputType of popup controlled by the trigger.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
dirInputText and interaction direction: ltr or rtl.
openInputInitial or controlled open state.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexInput/outputKeyboard 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

  • ng-navigation-menu

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

AttributeAccessPurpose
alignInputCross-axis alignment: start, center, or end.
aria-controlsOutputID of the element controlled by a trigger.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-hiddenInput/outputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
dirInputText and interaction direction: ltr or rtl.
disabledInputDisables native or component interaction.
openInputInitial or controlled open state.
roleInput/outputExplicit 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

VariablePurpose
--navigation-menu-content-offsetComponent 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

  • ng-range-slider

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

AttributeAccessPurpose
aria-orientationOutputInteraction axis exposed to assistive technology.
dirInputText and interaction direction: ltr or rtl.
maxInputMaximum native or component value.
minInputMinimum native or component value.
orientationInput/outputLayout 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

VariablePurpose
--range-endComponent styling variable.
--range-startComponent styling variable.
--valueComponent 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

  • ng-resizable-panel-group

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

AttributeAccessPurpose
aria-controlsOutputID of the element controlled by a trigger.
aria-disabledInputSemantic disabled state.
aria-orientationInput/outputInteraction axis exposed to assistive technology.
aria-valuemaxOutputMaximum value exposed by an adjustable control.
aria-valueminOutputMinimum value exposed by an adjustable control.
aria-valuenowOutputCurrent value exposed by an adjustable control.
data-max-sizeInputLargest panel flex size allowed during resizing.
data-min-sizeInputSmallest panel flex size allowed during resizing.
data-resizingOutputPresent while a pointer resize operation is active.
data-stepInputPanel flex-size increment used by keyboard resizing.
dirInputText and interaction direction: ltr or rtl.
orientationInput/outputResize axis: horizontal or vertical.
tabindexInput/outputKeyboard 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

VariablePurpose
--panel-sizeComponent 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 &amp; 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 &amp; 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

  • ng-sidebar

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

AttributeAccessPurpose
aria-controlsOutputID of the element controlled by a trigger.
aria-currentInputCurrent item or date state.
aria-expandedOutputOpen or expanded state exposed to assistive technology.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
collapsedInput/outputCurrent collapsed state.
collapsibleInput/outputCollapse behavior: offcanvas, icon, or none.
inertOutputPrevents interaction while the component is hidden.
responsiveInputCollapses an off-canvas sidebar below 48rem and expands it above that breakpoint.
roleInput/outputExplicit semantic role when native HTML does not provide one.
sideInput/outputPhysical placement: left or right.
variantInput/outputSurface 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

  • ng-tabs

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

AttributeAccessPurpose
aria-controlsOutputID of the element controlled by a trigger.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
aria-labelledbyOutputID of the element that supplies the accessible name.
aria-orientationInput/outputInteraction axis exposed to assistive technology.
aria-selectedInput/outputSelected item state.
dirInputText and interaction direction: ltr or rtl.
orientationInput/outputLayout direction: horizontal or vertical.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexOutputKeyboard 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

  • ng-toast

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

AttributeAccessPurpose
aria-atomicInput/outputWhether an assistive technology announces the entire updated region.
aria-describedbyInput/outputID of the element that supplies the accessible description.
aria-labelInput/outputAccessible name when visible text is insufficient.
aria-labelledbyInput/outputID of the element that supplies the accessible name.
aria-liveInput/outputAnnouncement priority for updates to a live region.
positionInput/outputViewport placement: top-left, top-center, top-right, bottom-left, bottom-center, or bottom-right.
roleInput/outputExplicit semantic role when native HTML does not provide one.
typeInput/outputToast 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

  • ng-toolbar

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

AttributeAccessPurpose
aria-disabledInput/outputSemantic disabled state.
aria-labelInputAccessible name when visible text is insufficient.
aria-orientationInput/outputInteraction axis exposed to assistive technology.
dirInputText and interaction direction: ltr or rtl.
disabledInputDisables native or component interaction.
hiddenInputNative visibility state observed when finding available items.
orientationInputLayout direction: horizontal or vertical.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexInput/outputKeyboard 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

  • ng-tooltip

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

AttributeAccessPurpose
aria-describedbyOutputID of the element that supplies the accessible description.
aria-hiddenOutputWhether generated or collapsed content is hidden from assistive technology.
openInputInitial or controlled open state.
roleOutputExplicit semantic role when native HTML does not provide one.
sideInput/outputPhysical 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

  • ng-tree

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

AttributeAccessPurpose
aria-disabledInput/outputSemantic disabled state.
aria-expandedInput/outputOpen or expanded state exposed to assistive technology.
aria-labelInputAccessible name when visible text is insufficient.
aria-labelledbyOutputID of the element that supplies the accessible name.
aria-multiselectableInputSet to true to allow Ctrl or Command click selection of several items.
aria-selectedInput/outputSelected item state.
data-valueInputApplication value included in angularcss:tree-select.
disabledInputDisables native or component interaction.
hiddenInputNative visibility state observed when finding available items.
roleOutputExplicit semantic role when native HTML does not provide one.
tabindexInput/outputKeyboard 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

  • angularcss:tree-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

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

  • Type: "angular.css"

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

FilePurpose
dist/angular-css.esm.jsESM entrypoint for bundlers.
dist/angular-css.umd.jsLocal browser script build.
dist/angular.cssCompiled component and token stylesheet.
@types/index.d.tsRoot 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

AttributeAccessPurpose
roleAuthoredExplicit semantic role when native HTML does not provide one.
sizeAuthoredCompact 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

  • .application-shell

Semantic structure

Use one .application-shell containing a direct semantic header, an existing Sidebar, and a direct main landmark. Existing components keep their own root selectors; no shell part classes are required.

API

Attributes and state

This component has no directive-specific attributes beyond its semantic HTML.

Attributes remain authored HTML, native state, or AngularTS inputs. AngularCSS does not write element state.

CSS custom properties

This styling hook does not define component-specific CSS custom properties.

DOM events

This component does not emit a component-specific custom event.

Native DOM events continue to work normally. AngularTS event directives such as ng-click and ng-keydown, plus the data-change model callback, remain application-owned.

Behavior

Application Shell composes a semantic header, Sidebar, and main landmark. Routing, session state, permissions, responsive navigation policy, and page content remain application-owned.

AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.

Accessibility

Prefer semantic landmarks and native elements inside the layout. Any interactive handles or triggers must retain an accessible name and visible focus indicator.

Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.

Customization

Target semantic elements, native state selectors, and component classes with ordinary CSS. Behavior and accessible state remain with native HTML and AngularTS; visual choices belong in the application stylesheet.

Read Customization for layer order, design tokens, state variants, and iframe demo isolation.

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:

StateHTML contract
LoadingSet aria-busy="true" on .data-table and replace the table region with Spinner, Skeleton, or Progress content.
EmptyKeep a direct explanatory paragraph or compose Empty after the filtered tbody has no rows.
ErrorPlace an Alert with aria-live="assertive" before the data region and retain filters for retry.
Permission limitedDisable unavailable native actions and connect the reason with aria-describedby.
Stale dataPlace a warning Alert with aria-live="polite" before the data region.
Filtering and pagingBind Filter Bar controls and Pagination links to application-owned query and page state.
Selection and bulk actionBind native checkboxes to row aria-selected and reveal one shared action menu when rows are selected.

AngularCSS styles these compositions without defining a request, cache, authorization, or data-source API.

Installation

Load the AngularCSS stylesheet. This entry needs no AngularCSS JavaScript or angular.css module dependency. Add AngularTS when using application bindings such as ng-model or ng-click. See Installation for the complete setup.

This entry uses native HTML and CSS. AngularCSS registers no runtime directive for it. Semantic table with application-owned data operations.

Anatomy

Root styling selector

  • .data-table

Semantic structure

Use .data-table on a section containing a semantic header, a figure with a native table, and an optional footer. Compose Filter Bar, Pagination, Checkbox, Button, Badge, Empty, Skeleton, and Progress without data-table part classes.

API

Attributes and state

AttributeAccessPurpose
aria-selectedAuthoredSelected row state.
aria-sortAuthoredColumn 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

VariablePurpose
--data-table-max-heightMaximum 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

  • .date-picker

Semantic structure

Use .date-picker around a visible label and the existing Popover and Calendar roots. The trigger may display an AngularTS-formatted value; no date-picker part classes are required.

API

Attributes and state

AttributeAccessPurpose
aria-invalidAuthoredValidation 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

  • .drawer

Semantic structure

Use .drawer as a wrapper containing a native invoker button and dialog with authored side. Close controls use command=close; the bottom handle is generated by CSS and no anatomy classes are required.

API

Attributes and state

AttributeAccessPurpose
dirAuthoredText and interaction direction: ltr or rtl.
sideAuthoredDialog edge: top, right, bottom, or left.
sizeAuthoredUse 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

  • form.form-layout

Semantic structure

Apply .form-layout to a native form containing semantic headers, fieldsets, Field patterns, an optional Validation Summary, and a footer. No form-layout part classes are required.

API

Attributes and state

AttributeAccessPurpose
columnsAuthoredPreferred 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

  • .master-detail

Semantic structure

Apply .master-detail and ng-resizable-panel-group to the same root. Use two direct sections separated by a labeled hr; place semantic navigation in the first and record content in the second.

API

Attributes and state

AttributeAccessPurpose
orientationAuthoredResizable 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

  • .sheet

Semantic structure

Use .sheet as a wrapper containing a native invoker button and dialog with authored side. Close controls use command=close; semantic headers, sections, forms, and footers need no anatomy classes.

API

Attributes and state

AttributeAccessPurpose
commandAuthoredNative invoker action such as show-modal or close.
dirAuthoredText and interaction direction: ltr or rtl.
sideAuthoredDialog edge: top, right, bottom, or left.
sizeAuthoredUse 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.