docs: add aria accordion examples

(cherry picked from commit c639f84347)
This commit is contained in:
Cheng-Hsuan Tsai 2025-11-18 09:52:12 +00:00 committed by Jessica Janiuk
parent afc25d1f70
commit ff6e9c0b7b
37 changed files with 1486 additions and 70 deletions

View file

@ -1,9 +0,0 @@
h1 {
background: #1e1e1e;
color: #e0e0e0;
padding: 2rem;
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
font-size: 2rem;
text-align: center;
}

View file

@ -1,8 +0,0 @@
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}

View file

@ -0,0 +1,94 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
position: relative;
}
h3:focus-within::before,
h3:hover::before {
content: '';
position: absolute;
height: 100%;
width: 2px;
background-color: var(--vivid-pink);
top: 0;
left: 0;
}
h3:not(:first-of-type) {
border-block-start: 1px solid var(--senary-contrast);
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-expanded='true'] {
background-image: var(--pink-to-purple-horizontal-gradient);
background-clip: text;
color: transparent;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
position: relative;
width: 1rem;
height: 1rem;
flex-shrink: 0;
margin-left: 1rem;
}
.expand-icon::before,
.expand-icon::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
top: 50%;
background-color: var(--quaternary-contrast);
transition: .3s ease-out;
}
.expand-icon::after {
transform: rotate(90deg);
}
.expand-icon__expanded::before {
transform: translateY(-50%) rotate(-90deg);
opacity: 0;
}
.expand-icon__expanded::after {
transform: translateY(-50%) rotate(0);
background-color: var(--electric-violet);
}

View file

@ -0,0 +1,61 @@
<div ngAccordionGroup class="basic-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger" [expanded]="true">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger" disabled>
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,75 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
border-block-start: 1px solid var(--quinary-contrast);
border-inline: 1px solid var(--quinary-contrast);
}
h3:focus-within,
h3:hover {
background-color: var(--septenary-contrast);
}
h3:first-of-type {
border-radius: 1rem 1rem 0 0;
}
h3:last-of-type {
border-block-end: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
}
h3:last-of-type:has([aria-expanded='true']) {
border-block-end: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
border-inline: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
border-block-end: 1px solid var(--quinary-contrast);
margin-block-end: 1rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
font-size: 1.5rem;
color: var(--quaternary-contrast);
transition: transform .3s ease-out;
}
.expand-icon__expanded {
transform: rotate(180deg);
}

View file

@ -0,0 +1,64 @@
<div ngAccordionGroup class="material-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger" [expanded]="true">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger" disabled>
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,83 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--symbolic-yellow) 90%, var(--gray-1000));
--retro-button-text-color: color-mix(in srgb, var(--symbolic-yellow) 10%, white);
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700);
--retro-flat-shadow:
4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700),
-4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--retro-button-text-color);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
h3:focus-within,
h3:hover {
box-shadow: var(--retro-pressed-shadow);
transform: translate(1px, 1px);
outline-offset: 6px;
outline: 4px dashed color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
h3:has([aria-disabled='true']) {
opacity: 0.5;
cursor: default;
}
.treasure-box {
margin: 0;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
background-color: var(--septenary-contrast);
box-shadow: var(--retro-flat-shadow);
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionPanel] {
padding: 1rem;
}

View file

@ -0,0 +1,49 @@
<div ngAccordionGroup class="retro-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger1.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger" disabled>
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger2.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger" [expanded]="true">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger3.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -1,9 +0,0 @@
h1 {
background: #1e1e1e;
color: #e0e0e0;
padding: 2rem;
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
font-size: 2rem;
text-align: center;
}

View file

@ -1 +0,0 @@
<h1>PLACEHOLDER</h1>

View file

@ -1,8 +0,0 @@
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}

View file

@ -0,0 +1,94 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
position: relative;
}
h3:focus-within::before,
h3:hover::before {
content: '';
position: absolute;
height: 100%;
width: 2px;
background-color: var(--vivid-pink);
top: 0;
left: 0;
}
h3:not(:first-of-type) {
border-block-start: 1px solid var(--senary-contrast);
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-expanded='true'] {
background-image: var(--pink-to-purple-horizontal-gradient);
background-clip: text;
color: transparent;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
position: relative;
width: 1rem;
height: 1rem;
flex-shrink: 0;
margin-left: 1rem;
}
.expand-icon::before,
.expand-icon::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
top: 50%;
background-color: var(--quaternary-contrast);
transition: .3s ease-out;
}
.expand-icon::after {
transform: rotate(90deg);
}
.expand-icon__expanded::before {
transform: translateY(-50%) rotate(-90deg);
opacity: 0;
}
.expand-icon__expanded::after {
transform: translateY(-50%) rotate(0);
background-color: var(--electric-violet);
}

View file

@ -0,0 +1,61 @@
<div ngAccordionGroup class="basic-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger" [expanded]="true">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger">
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger" [expanded]="true">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,75 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
border-block-start: 1px solid var(--quinary-contrast);
border-inline: 1px solid var(--quinary-contrast);
}
h3:focus-within,
h3:hover {
background-color: var(--septenary-contrast);
}
h3:first-of-type {
border-radius: 1rem 1rem 0 0;
}
h3:last-of-type {
border-block-end: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
}
h3:last-of-type:has([aria-expanded='true']) {
border-block-end: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
border-inline: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
border-block-end: 1px solid var(--quinary-contrast);
margin-block-end: 1rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
font-size: 1.5rem;
color: var(--quaternary-contrast);
transition: transform .3s ease-out;
}
.expand-icon__expanded {
transform: rotate(180deg);
}

View file

@ -0,0 +1,64 @@
<div ngAccordionGroup class="material-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger" [expanded]="true">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger">
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger" [expanded]="true">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,83 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--symbolic-yellow) 90%, var(--gray-1000));
--retro-button-text-color: color-mix(in srgb, var(--symbolic-yellow) 10%, white);
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700);
--retro-flat-shadow:
4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700),
-4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--retro-button-text-color);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
h3:focus-within,
h3:hover {
box-shadow: var(--retro-pressed-shadow);
transform: translate(1px, 1px);
outline-offset: 6px;
outline: 4px dashed color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
h3:has([aria-disabled='true']) {
opacity: 0.5;
cursor: default;
}
.treasure-box {
margin: 0;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
background-color: var(--septenary-contrast);
box-shadow: var(--retro-flat-shadow);
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionPanel] {
padding: 1rem;
}

View file

@ -0,0 +1,49 @@
<div ngAccordionGroup class="retro-accordion">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger1.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger2.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger3.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -1,9 +0,0 @@
h1 {
background: #1e1e1e;
color: #e0e0e0;
padding: 2rem;
margin: 0;
font-family: system-ui, -apple-system, sans-serif;
font-size: 2rem;
text-align: center;
}

View file

@ -1,8 +0,0 @@
import {Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.html',
styleUrl: './app.css',
})
export class App {}

View file

@ -0,0 +1,94 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
position: relative;
}
h3:focus-within::before,
h3:hover::before {
content: '';
position: absolute;
height: 100%;
width: 2px;
background-color: var(--vivid-pink);
top: 0;
left: 0;
}
h3:not(:first-of-type) {
border-block-start: 1px solid var(--senary-contrast);
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-expanded='true'] {
background-image: var(--pink-to-purple-horizontal-gradient);
background-clip: text;
color: transparent;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
position: relative;
width: 1rem;
height: 1rem;
flex-shrink: 0;
margin-left: 1rem;
}
.expand-icon::before,
.expand-icon::after {
content: '';
position: absolute;
width: 100%;
height: 2px;
top: 50%;
background-color: var(--quaternary-contrast);
transition: .3s ease-out;
}
.expand-icon::after {
transform: rotate(90deg);
}
.expand-icon__expanded::before {
transform: translateY(-50%) rotate(-90deg);
opacity: 0;
}
.expand-icon__expanded::after {
transform: translateY(-50%) rotate(0);
background-color: var(--electric-violet);
}

View file

@ -0,0 +1,61 @@
<div ngAccordionGroup class="basic-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger" [expanded]="true">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger">
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
></span>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,75 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: var(--inter-font);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--secondary-contrast);
box-sizing: border-box;
border-block-start: 1px solid var(--quinary-contrast);
border-inline: 1px solid var(--quinary-contrast);
}
h3:focus-within,
h3:hover {
background-color: var(--septenary-contrast);
}
h3:first-of-type {
border-radius: 1rem 1rem 0 0;
}
h3:last-of-type {
border-block-end: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
}
h3:last-of-type:has([aria-expanded='true']) {
border-block-end: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
p {
margin: 0;
padding: 0 1.5rem 1.5rem 1.5rem;
color: var(--tertiary-contrast);
font-size: 0.875rem;
border-inline: 1px solid var(--quinary-contrast);
border-radius: 0 0 1rem 1rem;
border-block-end: 1px solid var(--quinary-contrast);
margin-block-end: 1rem;
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionTrigger][aria-disabled='true'] {
opacity: 0.5;
cursor: default;
}
.expand-icon {
font-size: 1.5rem;
color: var(--quaternary-contrast);
transition: transform .3s ease-out;
}
.expand-icon__expanded {
transform: rotate(180deg);
}

View file

@ -0,0 +1,64 @@
<div ngAccordionGroup class="material-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger">
Which attribute tells assistive tech whether the panel is open or closed?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger1.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<p>
Use <code>aria-expanded</code> on the button element. Set it to "true" when the content
panel is visible and "false" when the content is hidden. This is a crucial state indicator
for screen reader users.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger" [expanded]="true">
How do you link the button to the content it controls?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger2.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<p>
Use the <code>aria-controls</code> attribute on the button, and set its value to match the
id of the related content panel. This establishes a programmatic relationship, allowing
assistive technologies to jump directly to the relevant content.
</p>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
What role should the heading element containing the accordion button have?
<span
aria-hidden="true"
class="material-symbols-outlined expand-icon"
[class.expand-icon__expanded]="trigger3.expanded()"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<p>
The element containing the button should typically have <code>role="heading"</code> with an
appropriate <code>aria-level</code> to define the structure. This ensures the accordion
section is recognized as a section header, making the page structure navigable for users.
</p>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -0,0 +1,83 @@
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--symbolic-yellow) 90%, var(--gray-1000));
--retro-button-text-color: color-mix(in srgb, var(--symbolic-yellow) 10%, white);
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700);
--retro-flat-shadow:
4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700),
-4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700),
0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700),
0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);
}
[ngAccordionGroup] {
width: 500px;
}
h3 {
font-size: 1rem;
margin: 0;
color: var(--retro-button-text-color);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
h3:focus-within,
h3:hover {
box-shadow: var(--retro-pressed-shadow);
transform: translate(1px, 1px);
outline-offset: 6px;
outline: 4px dashed color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
h3:has([aria-disabled='true']) {
opacity: 0.5;
cursor: default;
}
.treasure-box {
margin: 0;
padding: 1rem;
display: flex;
justify-content: center;
align-items: center;
height: 5rem;
background-color: var(--septenary-contrast);
box-shadow: var(--retro-flat-shadow);
}
[ngAccordionTrigger] {
display: flex;
align-items: center;
justify-content: space-between;
outline: none;
cursor: pointer;
padding: 1.5rem;
}
[ngAccordionPanel] {
padding: 1rem;
}

View file

@ -0,0 +1,49 @@
<div ngAccordionGroup class="retro-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger panelId="q1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger1.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q1">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q2" #trigger2="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger2.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q2">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger panelId="q3" #trigger3="ngAccordionTrigger">
Unlock Treasure Box
<span
aria-hidden="true"
class="material-symbols-outlined"
>{{trigger3.expanded() ? 'lock_open_right' : 'lock'}}</span
>
</span>
</h3>
<div ngAccordionPanel panelId="q3">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>

View file

@ -0,0 +1,15 @@
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrl: 'app.component.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}

View file

@ -5,10 +5,10 @@
An accordion organizes related content into expandable and collapsible sections, reducing page scrolling and helping users focus on relevant information. Each section has a trigger button and a content panel. Clicking a trigger toggles the visibility of its associated panel.
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.ts">
<docs-code header="app.ts" path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.ts"/>
<docs-code header="app.html" path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.html"/>
<docs-code header="app.css" path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.css"/>
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.css"/>
</docs-code-multifile>
<docs-pill-row>
@ -50,10 +50,29 @@ Accordions work well for organizing content into logical groups where users typi
Set `[multiExpandable]="false"` to allow only one panel to be open at a time. Opening a new panel automatically closes any previously open panel.
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.ts">
<docs-code header="app.ts" path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.ts"/>
<docs-code header="app.html" path="adev/src/content/examples/aria/accordion/src/single-expansion/app/app.html"/>
</docs-code-multifile>
<docs-tab-group>
<docs-tab label="Basic">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/single-expansion/basic/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Material">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/material/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/single-expansion/material/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/single-expansion/material/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/single-expansion/material/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Retro">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/single-expansion/retro/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/single-expansion/retro/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/single-expansion/retro/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/single-expansion/retro/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
</docs-tab-group>
This mode works well for FAQs or situations where you want users to focus on one answer at a time.
@ -61,10 +80,29 @@ This mode works well for FAQs or situations where you want users to focus on one
Set `[multiExpandable]="true"` to allow multiple panels to be open simultaneously. Users can expand as many panels as needed without closing others.
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/multi-expansion/app/app.ts">
<docs-code header="app.ts" path="adev/src/content/examples/aria/accordion/src/multi-expansion/app/app.ts"/>
<docs-code header="app.html" path="adev/src/content/examples/aria/accordion/src/multi-expansion/app/app.html"/>
</docs-code-multifile>
<docs-tab-group>
<docs-tab label="Basic">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/multi-expansion/basic/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/basic/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/multi-expansion/basic/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/basic/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Material">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/multi-expansion/material/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/material/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/multi-expansion/material/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/material/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Retro">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/multi-expansion/retro/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/retro/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/multi-expansion/retro/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/multi-expansion/retro/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
</docs-tab-group>
This mode is useful for form sections or when users need to compare content across multiple panels.
@ -74,10 +112,29 @@ NOTE: The `multiExpandable` input defaults to `true`. Set it to `false` explicit
Disable specific triggers using the `disabled` input. Control how disabled items behave during keyboard navigation using the `softDisabled` input on the accordion group.
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/disabled-focusable/app/app.ts">
<docs-code header="app.ts" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/app/app.ts"/>
<docs-code header="app.html" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/app/app.html"/>
</docs-code-multifile>
<docs-tab-group>
<docs-tab label="Basic">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/disabled-focusable/basic/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/basic/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/basic/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/basic/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Material">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/disabled-focusable/material/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/material/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/material/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/material/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
<docs-tab label="Retro">
<docs-code-multifile preview hideCode path="adev/src/content/examples/aria/accordion/src/disabled-focusable/retro/app/app.component.ts">
<docs-code header="TS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/retro/app/app.component.ts"/>
<docs-code header="HTML" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/retro/app/app.component.html"/>
<docs-code header="CSS" path="adev/src/content/examples/aria/accordion/src/disabled-focusable/retro/app/app.component.css"/>
</docs-code-multifile>
</docs-tab>
</docs-tab-group>
When `[softDisabled]="true"` (the default), disabled items can receive focus but cannot be activated. When `[softDisabled]="false"`, disabled items are skipped entirely during keyboard navigation.