diff --git a/packages/eui/src/components/context_menu/context_menu_panel.spec.tsx b/packages/eui/src/components/context_menu/context_menu_panel.spec.tsx index 9e41fb7d6db..425c72998c0 100644 --- a/packages/eui/src/components/context_menu/context_menu_panel.spec.tsx +++ b/packages/eui/src/components/context_menu/context_menu_panel.spec.tsx @@ -231,6 +231,52 @@ describe('EuiContextMenuPanel', () => { cy.focused().should('have.attr', 'data-test-subj', 'popoverToggle'); }); }); + + describe('disabling auto focus', () => { + it('does not focus anything if initialFocusedItemIndex is set to -1', () => { + cy.mount( + + {children} + + ); + cy.focused().should('not.exist'); + }); + + it('does not focus the back button if it exists', () => { + cy.mount( + {}} + title="Test" + items={items} + /> + ); + cy.focused().should('not.exist'); + }); + + it('still allows for manually tabbing to the panel and using up/down key navigation', () => { + cy.realMount( + + ); + cy.realPress('Tab'); + cy.focused().should('have.attr', 'data-test-subj', 'itemA'); + cy.realPress('{downarrow}'); + cy.focused().should('have.attr', 'data-test-subj', 'itemB'); + }); + + it('other children with `autoFocus` should take focus', () => { + cy.mount( + , + ]} + /> + ); + cy.focused().should('have.value', 'Auto focus test'); + }); + }); }); describe('Keyboard navigation of items', () => { diff --git a/packages/eui/src/components/context_menu/context_menu_panel.tsx b/packages/eui/src/components/context_menu/context_menu_panel.tsx index 578d42cd49c..fba84f9f41b 100644 --- a/packages/eui/src/components/context_menu/context_menu_panel.tsx +++ b/packages/eui/src/components/context_menu/context_menu_panel.tsx @@ -46,6 +46,12 @@ export type EuiContextMenuPanelProps = PropsWithChildren & HTMLAttributes, 'onKeyDown' | 'tabIndex' | 'onAnimationEnd' | 'title' > & { + /** + * Determines the initially focused menu item for keyboard and screen reader users. + * + * Can be set to `-1` to prevent autofocus (an uncommon case that must have + * keyboard accessibility accounted for manually if used) + */ initialFocusedItemIndex?: number; items?: ReactElement[]; onClose?: NoArgCallback; @@ -99,7 +105,9 @@ export class EuiContextMenuPanelClass extends Component< }, menuItems: [], focusedItemIndex: - props.onClose && props.initialFocusedItemIndex != null + props.onClose && + props.initialFocusedItemIndex != null && + props.initialFocusedItemIndex !== -1 ? props.initialFocusedItemIndex + 1 // Account for panel title back button : props.initialFocusedItemIndex, currentHeight: undefined, @@ -257,6 +265,13 @@ export class EuiContextMenuPanelClass extends Component< return; } + // `initialFocusedItemIndex={-1}` should only be used when preventing initial item focus is desired + if (this.state.focusedItemIndex === -1) { + // Resetting the focusedItemIndex to 0 allows keyboard up/down behavior to + // still work correctly later if the panel is manually tabbed into + return this.setState({ tookInitialFocus: true, focusedItemIndex: 0 }); + } + // If an item should be focused, focus it (if it exists) if (this.state.focusedItemIndex != null && this.state.menuItems.length) { const focusedItem = this.state.menuItems[this.state.focusedItemIndex];