Skip to content

Commit c5d9588

Browse files
brianferryNikki Massaro Kauffmanbennypowers
authored
fix(accordion): adding rti for keyboard navigation, removed internal navigation (#2493)
* fix(accordion): adding RTI to accordion, adding headers, removing old code * fix(accordion): adding RTI index after initialized * fix(accordion): removing older code for rti fix * chore: adding changeset * Merge branch `fix/accordion-rovingtabindex-controller` into `fix/accordion-rovingtabindex-controller` * fix(core): ensured rti arrow key listeners only apply to focusable items * fix(core): ensured rti error key listeners only apply to focusable items * fix(accordion): adding init items on mutation observer for RTI, removing tab tests * fix(tabs): reverting code change made locally * docs: update changeset * perf: defer computing composedPath() * test(accordion): adding test cases for rti navigation in nested, multiple accordions * fix(accordion): activeHeader a private accessor --------- Co-authored-by: Nikki Massaro Kauffman <[email protected]> Co-authored-by: Benny Powers <[email protected]> Co-authored-by: Benny Powers <[email protected]>
1 parent 1225e8e commit c5d9588

File tree

5 files changed

+279
-11
lines changed

5 files changed

+279
-11
lines changed

.changeset/brown-shirts-think.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@patternfly/pfe-core": patch
3+
---
4+
5+
**roving-tabindex-controller**: fixes arrow keydown event listeners
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
"@patternfly/elements": patch
3+
---
4+
`<pf-accordion>`: fixed keyboard navigation inside of nested accordions

core/pfe-core/controllers/roving-tabindex-controller.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@ export class RovingTabindexController<
9393
* handles keyboard navigation
9494
*/
9595
#onKeydown = (event: KeyboardEvent) => {
96-
if (event.ctrlKey || event.altKey || event.metaKey || this.#focusableItems.length < 1) {
96+
if (event.ctrlKey ||
97+
event.altKey ||
98+
event.metaKey ||
99+
!this.#focusableItems.length ||
100+
!event.composedPath().some(x =>
101+
this.#focusableItems.includes(x as ItemType))) {
97102
return;
98103
}
99-
100104
const item = this.activeItem;
101105
let shouldPreventDefault = false;
102106
const horizontalOnly =

elements/pf-accordion/BaseAccordion.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { Logger } from '@patternfly/pfe-core/controllers/logger.js';
1111
import { AccordionHeaderChangeEvent, BaseAccordionHeader } from './BaseAccordionHeader.js';
1212
import { BaseAccordionPanel } from './BaseAccordionPanel.js';
1313

14+
import { RovingTabindexController } from '@patternfly/pfe-core/controllers/roving-tabindex-controller.js';
15+
1416
import style from './BaseAccordion.css';
1517

1618
const CSS_TIMING_UNITS_RE = /^[0-9.]+(?<unit>[a-zA-Z]+)/g;
@@ -48,6 +50,8 @@ export abstract class BaseAccordion extends LitElement {
4850
return target instanceof BaseAccordionPanel;
4951
}
5052

53+
#headerIndex = new RovingTabindexController<BaseAccordionHeader>(this);
54+
5155
/**
5256
* Sets and reflects the currently expanded accordion 0-based indexes.
5357
* Use commas to separate multiple indexes.
@@ -78,6 +82,12 @@ export abstract class BaseAccordion extends LitElement {
7882
return this.#allPanels();
7983
}
8084

85+
get #activeHeader() {
86+
const { headers } = this;
87+
const index = headers.findIndex(header => header.matches(':focus,:focus-within'));
88+
return headers.at(index);
89+
}
90+
8191
protected expandedSets = new Set<number>();
8292

8393
#logger = new Logger(this);
@@ -103,7 +113,6 @@ export abstract class BaseAccordion extends LitElement {
103113
connectedCallback() {
104114
super.connectedCallback();
105115
this.addEventListener('change', this.#onChange as EventListener);
106-
this.addEventListener('keydown', this.#onKeydown);
107116
this.#mo.observe(this, { childList: true });
108117
this.#init();
109118
}
@@ -135,9 +144,18 @@ export abstract class BaseAccordion extends LitElement {
135144
*/
136145
async #init() {
137146
this.#initialized ||= !!await this.updateComplete;
147+
this.#headerIndex.initItems(this.headers);
148+
// Event listener to the accordion header after the accordion has been initialized to add the roving tabindex
149+
this.addEventListener('focusin', this.#updateActiveHeader as EventListener);
138150
this.updateAccessibility();
139151
}
140152

153+
#updateActiveHeader() {
154+
if (this.#activeHeader) {
155+
this.#headerIndex.updateActiveItem(this.#activeHeader);
156+
}
157+
}
158+
141159
#panelForHeader(header: BaseAccordionHeader) {
142160
const next = header.nextElementSibling;
143161
if (!BaseAccordion.isPanel(next)) {

0 commit comments

Comments
 (0)