Accordion
Genel Bakış
Bir akordeon, ilgili içeriği genişletilebilir ve daraltılabilir bölümlere düzenleyerek sayfa kaydırmayı azaltır ve kullanıcıların ilgili bilgilere odaklanmasına yardımcı olur. Her bölümün bir tetikleyici butonu ve bir içerik paneli vardır. Bir tetikleyiciye tıklamak, ilişkili panelin görünürlüğünü değiştirir.
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="basic-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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 #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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 #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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 #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
Kullanım
Akordeonlar, kullanıcıların genellikle aynı anda bir bölümü görüntülemeye ihtiyaç duydukları mantıksal gruplara içerik düzenleme için iyi çalışır.
Akordeon kullanin:
- Birden fazla soru ve yanıt içeren SSS gösterimi
- Uzun formları yönetilebilir bölümlere düzenleme
- İçerik ağırlıklı sayfalarda kaydırmayı azaltma
- İlgili bilgileri kademeli olarak açıklama
Akordeondan kacinin:
- Navigasyon menüleri oluştururken (bunun yerine Menu bileşenini kullanın)
- Sekmeli arayüzler oluştururken (bunun yerine Tabs bileşenini kullanın)
- Tek bir daraltılabilir bölüm gösterirken (bunun yerine bir açıklama kalıbı kullanın)
- Kullanıcıların aynı anda birden fazla bölümü görmesi gerektiğinde (farklı bir yerleşim düşünün)
Özellikler
- Genişleme modları - Aynı anda bir veya birden fazla panelin açık olup olmayacağını kontrol edin
- Klavye navigasyonu - Ok tuşları, Home ve End ile tetikleyiciler arasında gezinin
- Tembel render - İçerik yalnızca bir panel ilk kez genişletildiğinde oluşturulur, ilk yükleme performansını iyileştirir
- Devre dışı durumlar - Tüm grubu veya bireysel tetikleyicileri devre dışı bırakın
- Odak yönetimi - Devre dışı bırakılan öğelerin klavye odağı alıp alamayacağını kontrol edin
- Programatik kontrol - Bileşen kodunuzdan panelleri genişletin, daraltın veya değiştirin
- RTL desteği - Sağdan sola diller için otomatik destek
Örnekler
Tekli genişleme modu
Aynı anda yalnızca bir panelin açık olmasına izin vermek için [multiExpandable]="false" ayarlayın. Yeni bir panel açmak, daha önce açık olan paneli otomatik olarak kapatır.
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="basic-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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 #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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 #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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 #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="material-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="retro-accordion" [multiExpandable]="false">
<h3>
<span ngAccordionTrigger [panel]="panel1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger1.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel2" #trigger2="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger2.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel3" #trigger3="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger3.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>
CSS
@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(--page-background));
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[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;
}
Bu mod, SSS'ler veya kullanıcıların aynı anda bir yanıta odaklanmasını istediğiniz durumlar için iyi çalışır.
Çoklu genişleme modu
Birden fazla panelin aynı anda açık olmasına izin vermek için [multiExpandable]="true" ayarlayın. Kullanıcılar diğerlerini kapatmadan ihtiyaç duyduğu kadar panel genişletebilir.
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="basic-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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 #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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 #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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 #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="material-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="retro-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger1.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel2" #trigger2="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger2.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel3" #trigger3="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger3.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>
CSS
@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(--page-background));
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--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(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[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;
}
Bu mod, form bölümleri veya kullanıcıların birden fazla panel arasında içeriği karşılaştırması gerektiğinde kullanışlıdır.
NOTE: multiExpandable girdisi varsayılan olarak true'dur. Tek genişleme davranışı istiyorsanız açıkça false olarak ayarlayın.
Devre dışı akordeon öğeleri
disabled girdisini kullanarak belirli tetikleyicileri devre dışı bırakın. Devre dışı bırakılan öğelerin klavye navigasyonu sırasındaki davranışını akordeon grubundaki softDisabled girdisi ile kontrol edin.
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="basic-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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 #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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 #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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" #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="material-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<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 [panel]="panel2" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<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 [panel]="panel3" #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()"
translate="no"
>keyboard_arrow_up</span
>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<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>
CSS
@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);
}
TS
import {Component} from '@angular/core';
import {
AccordionGroup,
AccordionTrigger,
AccordionPanel,
AccordionContent,
} from '@angular/aria/accordion';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [AccordionGroup, AccordionTrigger, AccordionPanel, AccordionContent],
})
export class App {}
HTML
<div ngAccordionGroup class="retro-accordion">
<h3>
<span ngAccordionTrigger [panel]="panel1" #trigger1="ngAccordionTrigger">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger1.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">👻</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel2" #trigger2="ngAccordionTrigger" disabled>
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger2.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel2="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">💎💎💎</div>
</ng-template>
</div>
<h3>
<span ngAccordionTrigger [panel]="panel3" #trigger3="ngAccordionTrigger" [expanded]="true">
Unlock Treasure Box
<span aria-hidden="true" class="material-symbols-outlined" translate="no">{{
trigger3.expanded() ? 'lock_open_right' : 'lock'
}}</span>
</span>
</h3>
<div ngAccordionPanel #panel3="ngAccordionPanel">
<ng-template ngAccordionContent>
<div class="treasure-box">🐸 ribbit...ribbit...</div>
</ng-template>
</div>
</div>
CSS
@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(--page-background));
--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(--quaternary-contrast),
0px 4px 0px 0px var(--quaternary-contrast), -4px 0px 0px 0px var(--quaternary-contrast),
0px -4px 0px 0px var(--quaternary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--quaternary-contrast), 0px 4px 0px 0px var(--quaternary-contrast),
-4px 0px 0px 0px var(--quaternary-contrast), 0px -4px 0px 0px var(--quaternary-contrast);
--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(--quaternary-contrast),
0px 4px 0px 0px var(--quaternary-contrast), -4px 0px 0px 0px var(--quaternary-contrast),
0px -4px 0px 0px var(--quaternary-contrast), 8px 8px 0px 0px var(--quaternary-contrast);
--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(--quaternary-contrast),
0px 4px 0px 0px var(--quaternary-contrast), -4px 0px 0px 0px var(--quaternary-contrast),
0px -4px 0px 0px var(--quaternary-contrast), 0px 0px 0px 0px var(--quaternary-contrast);
}
[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;
}
[softDisabled]="true" olduğunda (varsayılan), devre dışı bırakılan öğeler odak alabilir ancak etkinleştirilemez. [softDisabled]="false" olduğunda, devre dışı bırakılan öğeler klavye navigasyonu sırasında tamamen atlanır.
Tembel içerik render etme
Panel ilk kez genişletilene kadar içerik render etmeyi ertelemek için bir ng-template üzerinde ngAccordionContent yönergesini kullanın. Bu, resimler, grafikler veya karmaşık bileşenler gibi ağır içerikli akordeonlar için performansı iyileştirir.
<div ngAccordionGroup>
<div>
<button ngAccordionTrigger [panel]="panel1">Trigger Text</button>
<div ngAccordionPanel #panel1="ngAccordionPanel">
<ng-template ngAccordionContent>
<!-- Bu içerik yalnızca panel ilk açıldığında render edilir -->
<img src="large-image.jpg" alt="Description" />
<app-expensive-component />
</ng-template>
</div>
</div>
</div>
Varsayılan olarak, panel daraltıldıktan sonra içerik DOM'da kalır. Panel kapatıldığında içeriği DOM'dan kaldırmak için [preserveContent]="false" ayarlayın.
Test etme
Angular Aria, akordeon bileşenlerini test etmek için bileşen harness'leri sağlar. İşte harness'lerin bir bileşen testinde nasıl kullanılacağına dair bir örnek:
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {AccordionGroupHarness} from '@angular/aria/accordion/testing';
import {MyAccordionComponent} from './my-accordion'; // Sizin bileşeniniz
describe('MyAccordionComponent', () => {
let fixture: ComponentFixture<MyAccordionComponent>;
let loader: HarnessLoader;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [MyAccordionComponent],
});
fixture = TestBed.createComponent(MyAccordionComponent);
await fixture.whenStable();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should allow expanding panels', async () => {
// Akordeon grubu harness'ini yükle
const group = await loader.getHarness(AccordionGroupHarness);
// Gruptaki tüm bireysel akordeonları (öğeleri) al
const accordions = await group.getAccordions();
expect(accordions.length).toBe(3);
// Başlangıç durumunu doğrula (ilki genişletilmiş, diğerleri daraltılmış)
expect(await accordions[0].isExpanded()).toBe(true);
expect(await accordions[1].isExpanded()).toBe(false);
// İkinci paneli genişlet
await accordions[1].expand();
// Güncellenmiş durumu doğrula
expect(await accordions[1].isExpanded()).toBe(true);
// multiExpandable false ise, ilki artık daraltılmış olmalı
expect(await accordions[0].isExpanded()).toBe(false);
});
});
API referansı
Ayrıntılı API belgeleri için aşağıdaki API referanslarını inceleyin: