diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx
index e49cbe2510f..eecc724a5d6 100644
--- a/src/components/Menu/MenuItem.tsx
+++ b/src/components/Menu/MenuItem.tsx
@@ -1,6 +1,13 @@
import { usePathWithoutHash } from '@/utils/usePathWithoutHash';
-import { ReactElement, useContext, useEffect, useState, useMemo } from 'react';
-import { Link as AmplifyUILink, Flex } from '@aws-amplify/ui-react';
+import {
+ ReactElement,
+ useContext,
+ useEffect,
+ useState,
+ useMemo,
+ useRef
+} from 'react';
+import { Link as AmplifyUILink, Button, Flex } from '@aws-amplify/ui-react';
import { IconExternalLink, IconChevron } from '@/components/Icons';
import Link from 'next/link';
import { JS_PLATFORMS, Platform, JSPlatform } from '@/data/platforms';
@@ -19,6 +26,7 @@ type MenuItemProps = {
level: number;
currentPlatform?: Platform;
hideChildren?: boolean;
+ tabIndex?: number;
};
function getPathname(route, currentPlatform: Platform | undefined) {
@@ -43,10 +51,45 @@ export function MenuItem({
const { menuOpen, toggleMenuOpen } = useContext(LayoutContext);
const asPathWithoutHash = usePathWithoutHash();
const [open, setOpen] = useState(false);
+ const ref = useRef(null);
const children = useMemo(
() => (hideChildren ? [] : pageNode.children),
[hideChildren, pageNode.children]
);
+
+ const makeSubsKeyboardAccessible = () => {
+ const pages = ref.current?.children[1]?.children;
+ for (const page of pages) {
+ const links = page.children[0].children;
+
+ for (const link of links) {
+ link.setAttribute('tabIndex', 0);
+ }
+
+ if (!page.children[1]?.classList.contains('menu__list--hide')) {
+ const subs = page.children[1]?.children;
+ if (subs) {
+ for (const sub of subs) {
+ sub.children[0].children[0].setAttribute('tabIndex', 0);
+ }
+ }
+ }
+ }
+ };
+
+ const makeSubsKeyboardInaccessible = () => {
+ const subItems = ref.current?.children[1];
+ const links = subItems?.getElementsByTagName('a');
+ const buttons = subItems?.getElementsByTagName('button');
+
+ for (const link of links) {
+ link.setAttribute('tabIndex', -1);
+ }
+ for (const button of buttons) {
+ button.setAttribute('tabIndex', -1);
+ }
+ };
+
const onLinkClick = () => {
// Category shouldn't be collapsible
if (
@@ -62,6 +105,17 @@ export function MenuItem({
}
};
+ const onCheveronClick = () => {
+ setOpen((prevOpen) => !prevOpen);
+
+ if (menuOpen) {
+ // Close the menu after clicking a link (applies to the mobile menu)
+ toggleMenuOpen(false);
+ } else {
+ toggleMenuOpen(true);
+ }
+ };
+
const handleFocus = () => {
if (parentSetOpen) {
parentSetOpen(true);
@@ -76,6 +130,26 @@ export function MenuItem({
let hideAPIResources = false;
+ useEffect(() => {
+ const current = ref.current;
+ if (
+ current?.children.length > 1 &&
+ open &&
+ !current?.classList.contains('menu__list-item--category')
+ ) {
+ makeSubsKeyboardAccessible();
+ } else if (
+ current?.children.length > 1 &&
+ !open &&
+ !current?.classList.contains('menu__list-item--category')
+ ) {
+ const pages = current?.children[1]?.children;
+ if (pages) {
+ makeSubsKeyboardInaccessible();
+ }
+ }
+ }, [open]);
+
useEffect(() => {
if (current) {
if (children && children.length > 0) {
@@ -158,6 +232,7 @@ export function MenuItem({
isExternal={true}
aria-label={pageNode.title + ' (opens in new tab)'}
onClick={onLinkClick}
+ tabIndex={level > Levels.Subcategory ? -1 : 0}
>