diff --git a/src/dev-app/BUILD.bazel b/src/dev-app/BUILD.bazel
index 3b10fb1d0a62..9de187b1630b 100644
--- a/src/dev-app/BUILD.bazel
+++ b/src/dev-app/BUILD.bazel
@@ -27,6 +27,8 @@ ng_project(
"//src/cdk/overlay",
"//src/dev-app/aria-accordion",
"//src/dev-app/aria-combobox",
+ "//src/dev-app/aria-docs-examples",
+ "//src/dev-app/aria-docs-examples/autocomplete:autocomplete-docs-demo",
"//src/dev-app/aria-grid",
"//src/dev-app/aria-listbox",
"//src/dev-app/aria-menu",
diff --git a/src/dev-app/aria-docs-examples/BUILD.bazel b/src/dev-app/aria-docs-examples/BUILD.bazel
new file mode 100644
index 000000000000..be9226f0b225
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/BUILD.bazel
@@ -0,0 +1,23 @@
+load("//tools:defaults.bzl", "ng_project")
+
+package(default_visibility = ["//visibility:public"])
+
+ng_project(
+ name = "aria-docs-examples",
+ srcs = glob(["**/*.ts"]),
+ assets = [
+ "aria-docs-examples.html",
+ "aria-docs-examples.css",
+ ],
+ deps = [
+ "//:node_modules/@angular/core",
+ "//src/components-examples/aria/accordion",
+ "//src/components-examples/aria/combobox",
+ "//src/components-examples/aria/grid",
+ "//src/components-examples/aria/listbox",
+ "//src/components-examples/aria/menu",
+ "//src/components-examples/aria/tabs",
+ "//src/components-examples/aria/toolbar",
+ "//src/components-examples/aria/tree",
+ ],
+)
diff --git a/src/dev-app/aria-docs-examples/aria-docs-examples.css b/src/dev-app/aria-docs-examples/aria-docs-examples.css
new file mode 100644
index 000000000000..3c984f1da14a
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/aria-docs-examples.css
@@ -0,0 +1,147 @@
+/** Accordion */
+
+[ngAccordionTrigger] {
+ display: inline-flex;
+ background: inherit;
+ border: none;
+ align-items: center;
+ font-size: inherit;
+ height: 36px;
+}
+
+[ngAccordionTrigger] svg {
+ width: 24px;
+ height: 24px;
+ transition: transform 0.2s ease-in-out;
+ transform: rotate(90deg);
+}
+
+[ngAccordionTrigger][aria-expanded='true'] svg {
+ transform: rotate(-90deg);
+}
+
+/** Grid */
+
+[ngGrid] {
+ display: flex;
+ flex-direction: column;
+}
+
+[ngGridRow] {
+ display: flex;
+ align-items: center;
+ height: 36px;
+}
+
+[ngGridCell] {
+ padding: 8px;
+}
+
+button[ngGridCellWidget] {
+ display: flex;
+ height: 36px;
+ width: 36px;
+ padding: 8px;
+}
+
+/** Combobox */
+
+[ngCombobox] .cdk-overlay-pane {
+ background: light-dark(white, black);
+ border: 1px solid;
+ padding: 8px;
+}
+
+[ngCombobox] [ngOption][aria-selected='true'] {
+ font-weight: bold;
+}
+
+[ngCombobox]:focus-within [ngOption][data-active='true'] {
+ border: 1px solid;
+}
+
+/** Listbox */
+
+[ngListbox] {
+ list-style-type: none;
+ padding: 0;
+}
+
+[ngOption] {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+
+[ngListbox]:focus-within [ngOption][data-active='true'] {
+ font-weight: bold;
+}
+
+[ngOption] .demo-selection-indicator {
+ font-size: 2rem;
+}
+
+[ngOption][aria-selected='false'] .demo-selection-indicator::before {
+ content: '-';
+}
+
+[ngOption][aria-selected='true'] .demo-selection-indicator::before {
+ content: '✓';
+}
+
+/** Menu */
+
+[ngMenuItem] {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ height: 36px;
+}
+
+/** Radio */
+
+[ngRadioGroup] {
+ list-style-type: none;
+ padding: 0;
+}
+
+[ngRadioButton] {
+ display: flex;
+ align-items: center;
+ height: 36px;
+ cursor: pointer;
+}
+
+[ngRadioButton] .demo-selection-indicator {
+ padding-right: 8px;
+}
+
+[ngRadioButton][aria-checked='true'] .demo-selection-indicator::before {
+ content: '◉';
+}
+
+[ngRadioButton][aria-checked='false'] .demo-selection-indicator::before {
+ content: '◯';
+}
+
+[ngTabList] {
+ list-style-type: none;
+ display: flex;
+ padding: 0;
+}
+
+[ngToolbar] {
+ display: flex;
+ height: 36px;
+ align-items: center;
+}
+
+[ngToolbar] [ngRadioGroup] {
+ display: flex;
+}
+
+/* Tree */
+
+[ngTreeItem][aria-expanded='false'] > [ngTreeItem] {
+ display: none;
+}
diff --git a/src/dev-app/aria-docs-examples/aria-docs-examples.html b/src/dev-app/aria-docs-examples/aria-docs-examples.html
new file mode 100644
index 000000000000..59a6f405c1ca
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/aria-docs-examples.html
@@ -0,0 +1,236 @@
+
Accordion
+
+
+
+
+
+
+
+
+ Angular Aria ensures your components start with an accessible-first
+ foundation.
+
+
+
+
+
+
+
+
+
+ Bring your own styles and design, however you want.
+
+
+
+
+
+
+
+
+ Automatically stay up-to-date with the latest best practices.
+
+
+
+
+Combobox
+
+
+
+
+
+
+
+ Apple
+
+
Banana
+
Orange
+
+
+
+
+Grid
+
+
+
+Listbox
+
+
+ -
+
+ T-rex and flamingos
+
+ -
+
+ G-bikes
+
+ -
+
+ Nap-pods
+
+
+
+Menu
+
+
+
Circles
+
Hangouts
+
Photos
+
Events
+
+
+Radio
+
+
+ -
+
+ Apple
+
+ -
+
+ Banana
+
+ -
+
+ Orange
+
+
+
+Tabs
+
+
+
+ - Jelly Bean
+ - Lollipop
+ - Pie
+
+
+
+ Smooth like butter
+
+
+
+ Goodbye Holo - welcome Material
+
+
+
+ Less pressing. More swiping
+
+
+
+Toolbar
+
+
+
+
+
+
+ -
+
+ Left
+
+ -
+
+ Center
+
+ -
+
+ Right
+
+
+
+
+Tree
+
+
+
+ Animals
+
+
+
+ Dog
+ Cat
+
+
+
Broccoli
+
diff --git a/src/dev-app/aria-docs-examples/aria-docs-examples.ts b/src/dev-app/aria-docs-examples/aria-docs-examples.ts
new file mode 100644
index 000000000000..f6bf54e6dfa9
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/aria-docs-examples.ts
@@ -0,0 +1,60 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import {ChangeDetectionStrategy, signal, Component, ViewEncapsulation} from '@angular/core';
+import {OverlayModule} from '@angular/cdk/overlay';
+import {
+ AccordionGroup,
+ AccordionTrigger,
+ AccordionPanel,
+ AccordionContent,
+} from '@angular/aria/accordion';
+import {Combobox, ComboboxInput, ComboboxPopupContainer} from '@angular/aria/combobox';
+import {Listbox, Option} from '@angular/aria/listbox';
+import {Grid, GridRow, GridCell, GridCellWidget} from '@angular/aria/grid';
+import {Menu, MenuItem} from '@angular/aria/menu';
+import {Tab, Tabs, TabList, TabPanel, TabContent} from '@angular/aria/tabs';
+import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar';
+import {Tree, TreeItem, TreeItemGroup} from '@angular/aria/tree';
+
+@Component({
+ templateUrl: 'aria-docs-examples.html',
+ styleUrl: 'aria-docs-examples.css',
+ imports: [
+ AccordionGroup,
+ AccordionTrigger,
+ AccordionPanel,
+ AccordionContent,
+ Combobox,
+ ComboboxInput,
+ Listbox,
+ Option,
+ Grid,
+ GridRow,
+ GridCell,
+ GridCellWidget,
+ Menu,
+ MenuItem,
+ TabList,
+ Tab,
+ Tabs,
+ TabPanel,
+ TabContent,
+ Toolbar,
+ ToolbarWidget,
+ Tree,
+ TreeItem,
+ TreeItemGroup,
+ OverlayModule,
+ ],
+ encapsulation: ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AriaDocsExamples {
+ open = signal(false);
+}
diff --git a/src/dev-app/aria-docs-examples/autocomplete/BUILD.bazel b/src/dev-app/aria-docs-examples/autocomplete/BUILD.bazel
new file mode 100644
index 000000000000..9b184e943680
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/autocomplete/BUILD.bazel
@@ -0,0 +1,23 @@
+load("//tools:defaults.bzl", "ng_project")
+
+package(default_visibility = ["//visibility:public"])
+
+ng_project(
+ name = "autocomplete-docs-demo",
+ srcs = glob(["**/*.ts"]),
+ assets = [
+ "autocomplete-docs-demo.html",
+ "autocomplete-docs-demo.css",
+ ],
+ deps = [
+ "//:node_modules/@angular/core",
+ "//src/components-examples/aria/accordion",
+ "//src/components-examples/aria/combobox",
+ "//src/components-examples/aria/grid",
+ "//src/components-examples/aria/listbox",
+ "//src/components-examples/aria/menu",
+ "//src/components-examples/aria/tabs",
+ "//src/components-examples/aria/toolbar",
+ "//src/components-examples/aria/tree",
+ ],
+)
diff --git a/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.css b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.css
new file mode 100644
index 000000000000..45fafe13bdff
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.css
@@ -0,0 +1,56 @@
+[ngComboboxInput] {
+ width: 300px;
+ padding: 8px;
+ border-width: 1px;
+ border-radius: 4px;
+ border-style: solid;
+}
+
+[ngCombobox]:focus-within [ngComboboxInput] {
+ border-color: blue;
+}
+
+[ngOption] {
+ cursor: pointer;
+ padding: 4px;
+ border-radius: 4px;
+ display: flex;
+ justify-content: space-between;
+}
+
+[ngOption][aria-selected='true'] {
+ content: '✓';
+ background: #ededff;
+ color: #5e5eff;
+}
+
+[ngOption][aria-selected='true']::after {
+ content: '✓';
+}
+
+[ngOption][data-active='true'],
+[ngOption]:hover {
+ background: #eaeaea;
+}
+
+[ngOption]:active {
+ background: #e5e5e5;
+}
+
+[popover] {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+
+[ngListbox] {
+ overflow: auto;
+ max-height: 300px;
+ border: 1px solid;
+ width: 100%;
+ padding: 4px;
+ border-radius: 4px;
+ /* Would be nice to inherit background but
+ its set to none by the cdk-overlay-popover */
+ background: white;
+}
diff --git a/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.html b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.html
new file mode 100644
index 000000000000..8c1b124edd7b
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ @for (biomeOption of biomeOptions(); track biomeOption) {
+
+ {{biomeOption.name}}
+
+ } @empty {
+ No matching biomes.
+ }
+
+
+
diff --git a/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.ts b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.ts
new file mode 100644
index 000000000000..4f703a78c7a1
--- /dev/null
+++ b/src/dev-app/aria-docs-examples/autocomplete/autocomplete-docs-demo.ts
@@ -0,0 +1,65 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import {
+ ChangeDetectionStrategy,
+ signal,
+ Component,
+ ViewEncapsulation,
+ viewChild,
+ afterRenderEffect,
+} from '@angular/core';
+import {OverlayModule} from '@angular/cdk/overlay';
+import {Combobox, ComboboxPopupContainer, ComboboxInput} from '@angular/aria/combobox';
+import {Listbox, Option} from '@angular/aria/listbox';
+
+const biomes = [
+ {name: 'Aquatic', id: 'aqu'},
+ {name: 'Forest', id: 'for'},
+ {name: 'Grassland', id: 'gra'},
+ {name: 'Desert', id: 'des'},
+ {name: 'Tunda', id: 'tun'},
+];
+
+@Component({
+ templateUrl: 'autocomplete-docs-demo.html',
+ styleUrl: 'autocomplete-docs-demo.css',
+ imports: [Combobox, ComboboxInput, Listbox, Option, OverlayModule],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AutocompleteDocsDemo {
+ listbox = viewChild>(Listbox);
+ combobox = viewChild>(Combobox);
+
+ initialValue = biomes[2];
+ biomeOptions = signal(biomes);
+ currentSelection = signal([this.initialValue.id]);
+
+ filterBiomes(inputValue: string) {
+ this.biomeOptions.set(
+ biomes.filter(b => b.name.toLowerCase().includes(inputValue.toLowerCase())),
+ );
+ }
+
+ resetOptions() {
+ this.biomeOptions.set(biomes);
+ }
+
+ constructor() {
+ afterRenderEffect(() => {
+ if (this.combobox()?.expanded()) {
+ this.listbox()?.scrollActiveItemIntoView();
+ }
+ });
+ afterRenderEffect(() => {
+ if (this.combobox()?.expanded()) {
+ this.resetOptions();
+ }
+ });
+ }
+}
diff --git a/src/dev-app/dev-app/dev-app-layout.ts b/src/dev-app/dev-app/dev-app-layout.ts
index a4db2af3a141..cc852302904c 100644
--- a/src/dev-app/dev-app/dev-app-layout.ts
+++ b/src/dev-app/dev-app/dev-app-layout.ts
@@ -62,6 +62,8 @@ export class DevAppLayout {
navItems = [
{name: 'Examples', route: '/examples'},
{name: 'CDK Dialog', route: '/cdk-dialog'},
+ {name: 'Aria Docs Autocomplete', route: '/aria-docs-autocomplete'},
+ {name: 'Aria Docs Examples', route: '/aria-docs-examples'},
{name: 'Aria Accordion', route: '/aria-accordion'},
{name: 'Aria Combobox', route: '/aria-combobox'},
{name: 'Aria Grid', route: '/aria-grid'},
diff --git a/src/dev-app/routes.ts b/src/dev-app/routes.ts
index e823b79b68a3..6c04adc9821f 100644
--- a/src/dev-app/routes.ts
+++ b/src/dev-app/routes.ts
@@ -7,6 +7,7 @@
*/
import {Routes} from '@angular/router';
+import {AutocompleteDocsDemo} from './aria-docs-examples/autocomplete/autocomplete-docs-demo';
import {DevApp404} from './dev-app/dev-app-404';
import {DevAppHome} from './dev-app/dev-app-home';
@@ -44,6 +45,18 @@ export const DEV_APP_ROUTES: Routes = [
path: 'aria-combobox',
loadComponent: () => import('./aria-combobox/combobox-demo').then(m => m.ComboboxDemo),
},
+ {
+ path: 'aria-docs-examples',
+ loadComponent: () =>
+ import('./aria-docs-examples/aria-docs-examples').then(m => m.AriaDocsExamples),
+ },
+ {
+ path: 'aria-docs-autocomplete',
+ loadComponent: () =>
+ import('./aria-docs-examples/autocomplete/autocomplete-docs-demo').then(
+ m => m.AutocompleteDocsDemo,
+ ),
+ },
{
path: 'aria-grid',
loadComponent: () => import('./aria-grid/grid-demo').then(m => m.GridDemo),