Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `loadLayout` now copies only the serialized tile properties: the spans, the positions, the flags and `id`. A layout from storage or a server can no longer set `innerHTML` on a tile or replace its prototype through `__proto__`. A value that is not an array, and an entry that is not an object, are ignored.

### Fixed
- #### Accordion
- The arrow keys, `Home` and `End` now skip a panel that does not render, such as a panel with the `hidden` attribute or `display: none`. Before, the focus stayed on the current panel.
- #### QR code
- Versions 30 to 40 at the `M` error correction level now use the data codeword counts of ISO/IEC 18004. Before, these codes had the wrong block structure.
- Without `error-level`, a logo larger than the safe area of level `M` now raises the error correction level to the smallest one that holds the logo, as documented. Before, the default `M` always applied, so the logo shrank. An explicit `error-level`, `M` included, still caps the logo.
Expand Down
51 changes: 51 additions & 0 deletions src/components/accordion/accordion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,57 @@ describe('Accordion', () => {
expect(panels[2].matches(':focus')).to.be.true;
});

it('should skip a hidden panel on ArrowDown keypress', async () => {
panels[1].hidden = true;

simulateKeyboard(panels[0], arrowDown);
await elementUpdated(accordion);

expect(panels[2].matches(':focus')).to.be.true;
});

it('should skip a hidden panel on ArrowUp keypress', async () => {
panels[1].hidden = true;

simulateKeyboard(panels[2], arrowUp);
await elementUpdated(accordion);

expect(panels[0].matches(':focus')).to.be.true;
});

it('should skip a panel that its styles do not render', async () => {
Comment thread
rkaraivanov marked this conversation as resolved.
panels[1].style.display = 'none';

simulateKeyboard(panels[0], arrowDown);
await elementUpdated(accordion);

expect(panels[2].matches(':focus')).to.be.true;
});

it('should navigate to the first rendered panel on Home keypress', async () => {
panels[0].hidden = true;

simulateClick(getPanelHeader(panels[2]));
await elementUpdated(accordion);

simulateKeyboard(panels[2], homeKey);
await elementUpdated(accordion);

expect(panels[1].matches(':focus')).to.be.true;
});

it('should navigate to the last rendered panel on End keypress', async () => {
panels[2].hidden = true;

simulateClick(getPanelHeader(panels[0]));
await elementUpdated(accordion);

simulateKeyboard(panels[0], endKey);
await elementUpdated(accordion);

expect(panels[1].matches(':focus')).to.be.true;
});

it('should navigate to the panel below on ArrowDown keypress', async () => {
for (let i = 0; i < panels.length; i++) {
simulateKeyboard(panels[i], arrowDown);
Expand Down
17 changes: 14 additions & 3 deletions src/components/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ export default class IgcAccordionComponent extends LitElement {
return this._panels.filter((panel) => !panel.disabled);
}

/**
* The interactive panels that the keyboard navigation can focus. A panel
* that is not rendered, for example with the `hidden` attribute, cannot
* take focus, so the navigation would stop at it.
*/
private get _navigablePanels(): IgcExpansionPanelComponent[] {
return this._interactivePanels.filter((panel) =>
this._getPanelHeader(panel)?.checkVisibility({ visibilityProperty: true })
);
}
Comment thread
Copilot marked this conversation as resolved.

//#endregion

//#region Public attributes and properties
Expand Down Expand Up @@ -115,11 +126,11 @@ export default class IgcAccordionComponent extends LitElement {
}

private _navigateToFirst(): void {
this._getPanelHeader(firstOf(this._interactivePanels))?.focus();
this._getPanelHeader(firstOf(this._navigablePanels))?.focus();
}

private _navigateToLast(): void {
this._getPanelHeader(lastOf(this._interactivePanels))?.focus();
this._getPanelHeader(lastOf(this._navigablePanels))?.focus();
}

private _navigateToPrevious(event: KeyboardEvent): void {
Expand Down Expand Up @@ -177,7 +188,7 @@ export default class IgcAccordionComponent extends LitElement {
panel: IgcExpansionPanelComponent,
dir: 1 | -1 = 1
): IgcExpansionPanelComponent {
const panels = this._interactivePanels;
const panels = this._navigablePanels;
const idx = panels.indexOf(panel);

return panels[idx + dir] || panel;
Expand Down
18 changes: 12 additions & 6 deletions src/components/accordion/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@

## Revision history

| Version | Date | Notes |
| ------: | ---------- | --------------------- |
| 1 | 2026-09-21 | Initial specification |
| Version | Date | Notes |
| ------: | ---------- | ---------------------------------------------- |
| 1 | 2026-09-21 | Initial specification |
| 2 | 2026-10-01 | The navigation skips panels that do not render |

## Overview

Expand Down Expand Up @@ -175,7 +176,8 @@ The keys apply while a panel header inside the accordion has focus.
| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Arrow Down</kbd> | Expands every panel, unless single expand is on. |
| <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>Arrow Up</kbd> | Collapses every panel. |

Disabled panels are skipped by the navigation.
The navigation skips disabled panels, and panels that do not render, for example a panel with the `hidden`
attribute or `display: none`.

## API

Expand Down Expand Up @@ -231,7 +233,8 @@ with `@open-wc/testing` fixtures and assertions. The groups below mirror the `de
the last.
8. <kbd>Alt</kbd> with the arrow keys expands and collapses the focused panel.
9. <kbd>Shift</kbd> + <kbd>Alt</kbd> with the arrow keys expands and collapses every panel.
10. Disabled panels are skipped by the navigation.
10. The navigation skips disabled panels, and panels that do not render, with the arrow keys and with <kbd>Home</kbd>
and <kbd>End</kbd>.

### Nested

Expand All @@ -242,14 +245,17 @@ with `@open-wc/testing` fixtures and assertions. The groups below mirror the `de
- Only direct `igc-expansion-panel` children are members of the accordion.
- The accordion has no expansion events of its own; the panels emit them.
- The accordion does not persist which panels were expanded.
- The navigation skips a panel that does not render, but <kbd>Shift</kbd> + <kbd>Alt</kbd> with the arrow keys,
`showAll` and `hideAll` still expand and collapse it.

## Accessibility

### ARIA roles and properties

- The accordion is a container; the header and region semantics come from the individual
[expansion panels](../expansion-panel/spec.md#aria-roles-and-properties).
- The panel headers form the navigable set, and disabled panels are announced as disabled and skipped.
- The panel headers form the navigable set. Disabled panels are announced as disabled and skipped, and panels that
do not render are skipped.

### Keyboard support

Expand Down
Loading