diff --git a/components/menu/src/flyout-menu/__tests__/flyout-menu.test.js b/components/menu/src/flyout-menu/__tests__/flyout-menu.test.js
new file mode 100644
index 0000000000..9ec5324015
--- /dev/null
+++ b/components/menu/src/flyout-menu/__tests__/flyout-menu.test.js
@@ -0,0 +1,48 @@
+import { render } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import React from 'react'
+import { MenuItem } from '../../menu-item/menu-item.js'
+import { FlyoutMenu } from '../flyout-menu.js'
+
+describe('Flyout Menu Component', () => {
+ it('can handle navigation of submenus', () => {
+ const { getByText, queryByText, getAllByRole } = render(
+
+
+
+
+ )
+
+ const itemOne = getByText(/Item 1/i)
+ const itemTwo = getByText(/Item 2/i)
+ let submenuChild = queryByText(/Item 2 a/i)
+
+ const menuItems = getAllByRole('menuitem')
+
+ expect(menuItems.length).toBe(2)
+ expect(menuItems[0]).toBe(itemOne.parentNode)
+ expect(menuItems[1]).toBe(itemTwo.parentNode)
+
+ expect(submenuChild).not.toBeInTheDocument()
+
+ userEvent.tab()
+ expect(menuItems[0].parentNode).toHaveFocus()
+ expect(menuItems[1].parentNode).not.toHaveFocus()
+
+ userEvent.keyboard('{ArrowDown}')
+ expect(menuItems[0].parentNode).not.toHaveFocus()
+ expect(menuItems[1].parentNode).toHaveFocus()
+
+ userEvent.keyboard('{ArrowRight}')
+ submenuChild = getByText(/Item 2 a/i)
+
+ expect(submenuChild).toBeInTheDocument()
+ expect(submenuChild.parentElement.parentElement).toHaveFocus()
+
+ userEvent.keyboard('{ArrowLeft}')
+ expect(queryByText(/Item 2 a/i)).not.toBeInTheDocument()
+ expect(menuItems[1].parentNode).toHaveFocus()
+ })
+})
diff --git a/components/menu/src/flyout-menu/flyout-menu.js b/components/menu/src/flyout-menu/flyout-menu.js
index c3b4035635..cae0ae6617 100644
--- a/components/menu/src/flyout-menu/flyout-menu.js
+++ b/components/menu/src/flyout-menu/flyout-menu.js
@@ -1,6 +1,13 @@
import { colors, elevations, spacers } from '@dhis2/ui-constants'
import PropTypes from 'prop-types'
-import React, { Children, cloneElement, isValidElement, useState } from 'react'
+import React, {
+ Children,
+ cloneElement,
+ isValidElement,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
import { Menu } from '../index.js'
const FlyoutMenu = ({
@@ -10,6 +17,7 @@ const FlyoutMenu = ({
dense,
maxHeight,
maxWidth,
+ closeMenu,
}) => {
const [openedSubMenu, setOpenedSubMenu] = useState(null)
const toggleSubMenu = (index) => {
@@ -17,8 +25,45 @@ const FlyoutMenu = ({
setOpenedSubMenu(toggleValue)
}
+ const divRef = useRef(null)
+
+ useEffect(() => {
+ if (!divRef.current) {
+ return
+ }
+ const div = divRef.current
+
+ const handleFocus = (event) => {
+ if (event.target === div) {
+ if (div?.children && div.children.length > 0) {
+ div.children[0].focus()
+ }
+ }
+ }
+
+ const handleKeyDown = (event) => {
+ if (event.key === 'Escape') {
+ event.preventDefault()
+ closeMenu && closeMenu()
+ }
+ }
+
+ div.addEventListener('focus', handleFocus)
+ div.addEventListener('keydown', handleKeyDown)
+
+ return () => {
+ div.removeEventListener('focus', handleFocus)
+ div.removeEventListener('keydown', handleKeyDown)
+ }
+ }, [closeMenu])
+
return (
-
+