Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

- Updated `testenv` mock for `EuiIcon` to render `aria-label` as text ([#5709](https://github.com/elastic/eui/pull/5709))

**Bug fixes**

- Fixed `EuiContextMenu` requiring two tab keypresses to advance to the next focusable menu item ([#5719](https://github.com/elastic/eui/pull/5719))

**Breaking changes**

- Removed Legacy theme including compiled CSS ([#5688](https://github.com/elastic/eui/pull/5688))
Expand Down
26 changes: 26 additions & 0 deletions src/components/context_menu/context_menu_panel.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,32 @@ describe('EuiContextMenuPanel', () => {
});
});
});

describe('tab key', () => {
beforeEach(() => {
cy.mount(<EuiContextMenuPanel items={items} />);
});

it('tab key focuses the first menu item', () => {
cy.focused().should('have.attr', 'class', 'euiContextMenuPanel');
cy.realPress('Tab');
cy.focused().should('have.attr', 'data-test-subj', 'itemA');
});

it('subsequently, tab key focuses the next menu item', () => {
cy.focused().should('have.attr', 'class', 'euiContextMenuPanel');
cy.repeatRealPress('Tab');
cy.focused().should('have.attr', 'data-test-subj', 'itemB');
});

it('shift+tab key focuses the previous menu item', () => {
cy.focused().should('have.attr', 'class', 'euiContextMenuPanel');
cy.repeatRealPress('Tab');
cy.focused().should('have.attr', 'data-test-subj', 'itemB');
cy.realPress(['Shift', 'Tab']);
cy.focused().should('have.attr', 'data-test-subj', 'itemA');
});
});
});

describe('Automated accessibility check', () => {
Expand Down
25 changes: 14 additions & 11 deletions src/components/context_menu/context_menu_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,20 @@ export class EuiContextMenuPanel extends Component<Props, State> {
if (this.props.items && this.props.items.length) {
switch (event.key) {
case cascadingMenuKeys.TAB:
// We need to sync up with the user if s/he is tabbing through the items.
const focusedItemIndex = this.state.menuItems.indexOf(
document.activeElement as HTMLElement
);

this.setState({
focusedItemIndex:
focusedItemIndex >= 0 &&
focusedItemIndex < this.state.menuItems.length
? focusedItemIndex
: undefined,
requestAnimationFrame(() => {
// NOTE: document.activeElement is stale if not wrapped in a setTimeout
Comment thread
cee-chen marked this conversation as resolved.
Outdated
const focusedItemIndex = this.state.menuItems.indexOf(
document.activeElement as HTMLElement
);

// We need to sync our internal state with the user tabbing through items
this.setState({
focusedItemIndex:
focusedItemIndex >= 0 &&
focusedItemIndex < this.state.menuItems.length
? focusedItemIndex
: undefined,
});
});
break;

Expand Down