Skip to content

Commit 0270c9f

Browse files
committed
feat(aria/accordion): add label inputs coordinated by LabelControl
1 parent 812ce2f commit 0270c9f

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

goldens/aria/accordion/index.api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,14 @@ export class AccordionPanel {
4343
readonly element: HTMLElement;
4444
expand(): void;
4545
readonly id: _angular_core.InputSignal<string>;
46+
readonly label: _angular_core.InputSignal<string | undefined>;
47+
readonly _labelControl: LabelControl;
48+
readonly labelledBy: _angular_core.InputSignal<string[]>;
4649
_pattern?: AccordionTriggerPattern;
4750
toggle(): void;
4851
readonly visible: _angular_core.Signal<boolean>;
4952
// (undocumented)
50-
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AccordionPanel, "[ngAccordionPanel]", ["ngAccordionPanel"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
53+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<AccordionPanel, "[ngAccordionPanel]", ["ngAccordionPanel"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "labelledBy": { "alias": "labelledBy"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof DeferredContentAware; inputs: { "preserveContent": "preserveContent"; }; outputs: {}; }]>;
5154
// (undocumented)
5255
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AccordionPanel, never>;
5356
}

src/aria/accordion/accordion-panel.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {Directive, ElementRef, afterRenderEffect, computed, inject, input} from '@angular/core';
1010
import {_IdGenerator} from '@angular/cdk/a11y';
11-
import {DeferredContentAware, AccordionTriggerPattern} from '../private';
11+
import {AccordionTriggerPattern, DeferredContentAware, LabelControl} from '../private';
1212

1313
/**
1414
* The content panel of an accordion item that is conditionally visible.
@@ -43,7 +43,8 @@ import {DeferredContentAware, AccordionTriggerPattern} from '../private';
4343
host: {
4444
'role': 'region',
4545
'[attr.id]': 'id()',
46-
'[attr.aria-labelledby]': '_pattern?.id()',
46+
'[attr.aria-label]': '_labelControl.label()',
47+
'[attr.aria-labelledby]': '_labelControl.labelledBy()',
4748
'[attr.inert]': '!visible() ? true : null',
4849
},
4950
})
@@ -57,9 +58,18 @@ export class AccordionPanel {
5758
/** The DeferredContentAware host directive. */
5859
private readonly _deferredContentAware = inject(DeferredContentAware);
5960

61+
/** Controls label for this tabpanel. */
62+
readonly _labelControl: LabelControl;
63+
6064
/** A global unique identifier for the panel. */
6165
readonly id = input(inject(_IdGenerator).getId('ng-accordion-panel-', true));
6266

67+
/** The (optional) label for the accordion panel. */
68+
readonly label = input<string | undefined>(undefined);
69+
70+
/** The (optional) labelledBy ids for the accordion panel. */
71+
readonly labelledBy = input<string[]>([]);
72+
6373
/** Whether the accordion panel is visible. True if the associated trigger is expanded. */
6474
readonly visible = computed(() => this._pattern?.expanded() === true);
6575

@@ -71,6 +81,12 @@ export class AccordionPanel {
7181
_pattern?: AccordionTriggerPattern;
7282

7383
constructor() {
84+
this._labelControl = new LabelControl({
85+
defaultLabelledBy: computed(() => this._pattern!.id()),
86+
label: this.label,
87+
labelledBy: this.labelledBy,
88+
});
89+
7490
// Connect the panel's hidden state to the DeferredContentAware's visibility.
7591
afterRenderEffect({
7692
write: () => {

0 commit comments

Comments
 (0)