diff --git a/client/common/ButtonOrLink.jsx b/client/common/ButtonOrLink.jsx
index 924f108024..f759aa8ffb 100644
--- a/client/common/ButtonOrLink.jsx
+++ b/client/common/ButtonOrLink.jsx
@@ -5,23 +5,60 @@ import PropTypes from 'prop-types';
 /**
  * Helper for switching between <button>, <a>, and <Link>
  */
-const ButtonOrLink = ({ href, children, ...props }) => {
-  if (href) {
-    if (href.startsWith('http')) {
+
+const ButtonOrLink = React.forwardRef(
+  ({ href, children, isDisabled, onClick, ...props }, ref) => {
+    const handleClick = (e) => {
+      if (isDisabled) {
+        e.preventDefault();
+        e.stopPropagation();
+        return;
+      }
+      if (onClick) {
+        onClick(e);
+      }
+    };
+
+    if (href) {
+      if (href.startsWith('http')) {
+        return (
+          <a
+            ref={ref}
+            href={href}
+            target="_blank"
+            rel="noopener noreferrer"
+            aria-disabled={isDisabled}
+            {...props}
+            onClick={handleClick}
+          >
+            {children}
+          </a>
+        );
+      }
       return (
-        <a href={href} target="_blank" rel="noopener noreferrer" {...props}>
+        <Link
+          ref={ref}
+          to={href}
+          aria-disabled={isDisabled}
+          {...props}
+          onClick={handleClick}
+        >
           {children}
-        </a>
+        </Link>
       );
     }
     return (
-      <Link to={href} {...props}>
+      <button
+        ref={ref}
+        aria-disabled={isDisabled}
+        {...props}
+        onClick={handleClick}
+      >
         {children}
-      </Link>
+      </button>
     );
   }
-  return <button {...props}>{children}</button>;
-};
+);
 
 /**
  * Accepts all the props of an HTML <a> or <button> tag.
@@ -34,15 +71,19 @@ ButtonOrLink.propTypes = {
    * External links should start with 'http' or 'https' and will open in a new window.
    */
   href: PropTypes.string,
+  isDisabled: PropTypes.bool,
   /**
    * Content of the button/link.
    * Can be either a string or a complex element.
    */
-  children: PropTypes.node.isRequired
+  children: PropTypes.node.isRequired,
+  onClick: PropTypes.func
 };
 
 ButtonOrLink.defaultProps = {
-  href: null
+  href: null,
+  isDisabled: false,
+  onClick: null
 };
 
 export default ButtonOrLink;
diff --git a/client/common/ButtonOrLink.test.jsx b/client/common/ButtonOrLink.test.jsx
index 0e6fb093b4..7b1a6326a4 100644
--- a/client/common/ButtonOrLink.test.jsx
+++ b/client/common/ButtonOrLink.test.jsx
@@ -13,7 +13,7 @@ describe('ButtonOrLink', () => {
     render(<ButtonOrLink onClick={clickHandler}>Text</ButtonOrLink>);
     const button = screen.getByRole('button');
     expect(button).toBeInstanceOf(HTMLButtonElement);
-    expect(button).toContainHTML('<button>Text</button>');
+    expect(button).toContainHTML('<button aria-disabled="false">Text</button>');
     fireEvent.click(button);
     expect(clickHandler).toHaveBeenCalled();
   });
diff --git a/client/common/usePrevious.js b/client/common/usePrevious.js
new file mode 100644
index 0000000000..ed46581cb0
--- /dev/null
+++ b/client/common/usePrevious.js
@@ -0,0 +1,11 @@
+import { useEffect, useRef } from 'react';
+
+export default function usePrevious(value) {
+  const ref = useRef();
+
+  useEffect(() => {
+    ref.current = value;
+  }, [value]);
+
+  return ref.current;
+}
diff --git a/client/components/Menubar/Menubar.jsx b/client/components/Menubar/Menubar.jsx
index b806246515..8d7ff38da0 100644
--- a/client/components/Menubar/Menubar.jsx
+++ b/client/components/Menubar/Menubar.jsx
@@ -1,19 +1,135 @@
 import PropTypes from 'prop-types';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
+import React, {
+  useCallback,
+  useMemo,
+  useRef,
+  useState,
+  useEffect
+} from 'react';
 import useModalClose from '../../common/useModalClose';
 import { MenuOpenContext, MenubarContext } from './contexts';
+import usePrevious from '../../common/usePrevious';
+
+/**
+ * @component
+ * @param {object} props
+ * @param {React.ReactNode} props.children - Menu items that will be rendered in the menubar
+ * @param {string} [props.className='nav__menubar'] - CSS class name to apply to the menubar
+ * @returns {JSX.Element}
+ */
+
+/**
+ * Menubar manages a collection of menu items and their submenus. It provides keyboard navigation,
+ * focus and state management, and other accessibility features for the menu items and submenus.
+ *
+ * @example
+ * <Menubar>
+ *  <MenubarSubmenu id="file" title="File">
+ *  ... menu items
+ *  </MenubarSubmenu>
+ * </Menubar>
+ */
 
 function Menubar({ children, className }) {
+  // core state for menu management
   const [menuOpen, setMenuOpen] = useState('none');
+  const [activeIndex, setActiveIndex] = useState(0);
+  const prevIndex = usePrevious(activeIndex);
+  const [hasFocus, setHasFocus] = useState(false);
 
+  // refs for menu items and their ids
+  const menuItems = useRef(new Set()).current;
+  const menuItemToId = useRef(new Map()).current;
+
+  // ref for hiding submenus
   const timerRef = useRef(null);
 
-  const handleClose = useCallback(() => {
+  // get the id of a menu item by its index
+  const getMenuId = useCallback(
+    (index) => {
+      const items = Array.from(menuItems);
+      const itemNode = items[index];
+      return menuItemToId.get(itemNode);
+    },
+    [menuItems, menuItemToId, activeIndex]
+  );
+
+  /**
+   * navigation functions
+   */
+  const prev = useCallback(() => {
+    const newIndex = (activeIndex - 1 + menuItems.size) % menuItems.size;
+    setActiveIndex(newIndex);
+
+    if (menuOpen !== 'none') {
+      const newMenuId = getMenuId(newIndex);
+      setMenuOpen(newMenuId);
+    }
+  }, [activeIndex, menuItems, menuOpen, getMenuId]);
+
+  const next = useCallback(() => {
+    const newIndex = (activeIndex + 1) % menuItems.size;
+    setActiveIndex(newIndex);
+
+    if (menuOpen !== 'none') {
+      const newMenuId = getMenuId(newIndex);
+      setMenuOpen(newMenuId);
+    }
+  }, [activeIndex, menuItems, menuOpen, getMenuId]);
+
+  const first = useCallback(() => {
+    setActiveIndex(0);
+  }, []);
+
+  const last = useCallback(() => {
+    setActiveIndex(menuItems.size - 1);
+  }, []);
+
+  // closes the menu and returns focus to the active menu item
+  // is called on Escape key press
+  const close = useCallback(() => {
+    if (menuOpen === 'none') return;
+
+    const items = Array.from(menuItems);
+    const activeNode = items[activeIndex];
     setMenuOpen('none');
-  }, [setMenuOpen]);
+    activeNode.focus();
+  }, [activeIndex, menuItems, menuOpen]);
 
-  const nodeRef = useModalClose(handleClose);
+  // toggle the open state of a submenu
+  const toggleMenuOpen = useCallback((id) => {
+    setMenuOpen((prevState) => (prevState === id ? 'none' : id));
+  });
+
+  /**
+   * Register top level menu items. Stores both the DOM node and the id of the submenu.
+   * Access to the DOM node is needed for focus management and tabindex control,
+   * while the id is needed to toggle the submenu open and closed.
+   *
+   * @param {React.RefObject} ref - a ref to the DOM node of the menu item
+   * @param {string} submenuId - the id of the submenu that the menu item opens
+   *
+   */
+  const registerTopLevelItem = useCallback(
+    (ref, submenuId) => {
+      const menuItemNode = ref.current;
 
+      if (menuItemNode) {
+        menuItems.add(menuItemNode);
+        menuItemToId.set(menuItemNode, submenuId); // store the id of the submenu
+      }
+
+      return () => {
+        menuItems.delete(menuItemNode);
+        menuItemToId.delete(menuItemNode);
+      };
+    },
+    [menuItems, menuItemToId]
+  );
+
+  /**
+   * focus and blur management
+   */
   const clearHideTimeout = useCallback(() => {
     if (timerRef.current) {
       clearTimeout(timerRef.current);
@@ -21,17 +137,89 @@ function Menubar({ children, className }) {
     }
   }, [timerRef]);
 
-  const handleBlur = useCallback(() => {
-    timerRef.current = setTimeout(() => setMenuOpen('none'), 10);
-  }, [timerRef, setMenuOpen]);
+  const handleClose = useCallback(() => {
+    clearHideTimeout();
+    setMenuOpen('none');
+  }, [setMenuOpen]);
+
+  const nodeRef = useModalClose(handleClose);
+
+  const handleFocus = useCallback(() => {
+    setHasFocus(true);
+  }, []);
 
-  const toggleMenuOpen = useCallback(
-    (menu) => {
-      setMenuOpen((prevState) => (prevState === menu ? 'none' : menu));
+  const handleBlur = useCallback(
+    (e) => {
+      const isInMenu = nodeRef.current?.contains(document.activeElement);
+
+      if (!isInMenu) {
+        timerRef.current = setTimeout(() => {
+          if (nodeRef.current) {
+            setMenuOpen('none');
+            setHasFocus(false);
+          }
+        }, 10);
+      }
     },
-    [setMenuOpen]
+    [nodeRef]
   );
 
+  // keyboard navigation
+  const keyHandlers = {
+    ArrowLeft: (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      prev();
+    },
+    ArrowRight: (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      next();
+    },
+    Escape: (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      close();
+    },
+    Tab: (e) => {
+      e.stopPropagation();
+      // close
+    },
+    Home: (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      first();
+    },
+    End: (e) => {
+      e.preventDefault();
+      e.stopPropagation();
+      last();
+    }
+    // to do: support direct access keys
+  };
+
+  // focus the active menu item and set its tabindex
+  useEffect(() => {
+    if (activeIndex !== prevIndex) {
+      const items = Array.from(menuItems);
+      const activeNode = items[activeIndex];
+      const prevNode = items[prevIndex];
+
+      // roving tabindex
+      prevNode?.setAttribute('tabindex', '-1');
+      activeNode?.setAttribute('tabindex', '0');
+
+      if (hasFocus) {
+        activeNode?.focus();
+      }
+    }
+  }, [activeIndex, prevIndex, menuItems]);
+
+  useEffect(() => {
+    clearHideTimeout();
+  }, [clearHideTimeout]);
+
+  // context value for dropdowns and menu items
   const contextValue = useMemo(
     () => ({
       createMenuHandlers: (menu) => ({
@@ -40,6 +228,15 @@ function Menubar({ children, className }) {
         },
         onClick: () => {
           toggleMenuOpen(menu);
+          const items = Array.from(menuItems);
+          const index = items.findIndex(
+            (item) => menuItemToId.get(item) === menu
+          );
+          const item = items[index];
+          if (index !== -1) {
+            setActiveIndex(index);
+            item.focus();
+          }
         },
         onBlur: handleBlur,
         onFocus: clearHideTimeout
@@ -49,6 +246,16 @@ function Menubar({ children, className }) {
           if (e.button === 2) {
             return;
           }
+
+          const isDisabled =
+            e.currentTarget.getAttribute('aria-disabled') === 'true';
+
+          if (isDisabled) {
+            e.preventDefault();
+            e.stopPropagation();
+            return;
+          }
+
           setMenuOpen('none');
         },
         onBlur: handleBlur,
@@ -57,18 +264,48 @@ function Menubar({ children, className }) {
           setMenuOpen(menu);
         }
       }),
-      toggleMenuOpen
+      menuItems,
+      activeIndex,
+      setActiveIndex,
+      registerTopLevelItem,
+      setMenuOpen,
+      toggleMenuOpen,
+      hasFocus,
+      setHasFocus
     }),
-    [setMenuOpen, toggleMenuOpen, clearHideTimeout, handleBlur]
+    [
+      menuItems,
+      activeIndex,
+      setActiveIndex,
+      registerTopLevelItem,
+      menuOpen,
+      toggleMenuOpen,
+      hasFocus,
+      setHasFocus,
+      clearHideTimeout,
+      handleBlur
+    ]
   );
 
   return (
     <MenubarContext.Provider value={contextValue}>
-      <div className={className} ref={nodeRef}>
+      <ul
+        className={className}
+        role="menubar"
+        ref={nodeRef}
+        aria-orientation="horizontal"
+        onFocus={handleFocus}
+        onKeyDown={(e) => {
+          const handler = keyHandlers[e.key];
+          if (handler) {
+            handler(e);
+          }
+        }}
+      >
         <MenuOpenContext.Provider value={menuOpen}>
           {children}
         </MenuOpenContext.Provider>
-      </div>
+      </ul>
     </MenubarContext.Provider>
   );
 }
@@ -80,7 +317,7 @@ Menubar.propTypes = {
 
 Menubar.defaultProps = {
   children: null,
-  className: 'nav'
+  className: 'nav__menubar'
 };
 
 export default Menubar;
diff --git a/client/components/Menubar/Menubar.test.jsx b/client/components/Menubar/Menubar.test.jsx
new file mode 100644
index 0000000000..0f78d2f547
--- /dev/null
+++ b/client/components/Menubar/Menubar.test.jsx
@@ -0,0 +1,155 @@
+import React from 'react';
+import { render, screen, fireEvent } from '../../test-utils';
+import Menubar from './Menubar';
+import MenubarSubmenu from './MenubarSubmenu';
+import MenubarItem from './MenubarItem';
+
+describe('Menubar', () => {
+  const renderMenubar = () => {
+    render(
+      <Menubar>
+        <MenubarSubmenu id="file" title="File">
+          <MenubarItem id="file-new" title="New" onClick={jest.fn()}>
+            New
+          </MenubarItem>
+          <MenubarItem id="file-save" title="Save" onClick={jest.fn()}>
+            Save
+          </MenubarItem>
+          <MenubarItem id="file-open" title="Open" onClick={jest.fn()}>
+            Open
+          </MenubarItem>
+        </MenubarSubmenu>
+        <MenubarSubmenu id="edit" title="Edit">
+          <MenubarItem id="edit-tidy" title="Tidy" onClick={jest.fn()}>
+            Tidy
+          </MenubarItem>
+          <MenubarItem id="edit-find" title="Find" onClick={jest.fn()}>
+            Find
+          </MenubarItem>
+          <MenubarItem id="edit-replace" title="Replace" onClick={jest.fn()}>
+            Replace
+          </MenubarItem>
+        </MenubarSubmenu>
+      </Menubar>
+    );
+  };
+
+  it('should render a menubar with submenu triggers', () => {
+    renderMenubar();
+
+    const fileMenuTrigger = screen.getByRole('menuitem', { name: 'File' });
+    const editMenuTrigger = screen.getByRole('menuitem', { name: 'Edit' });
+
+    expect(fileMenuTrigger).toBeInTheDocument();
+    expect(editMenuTrigger).toBeInTheDocument();
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+  });
+
+  it('should open a submenu when clicked', () => {
+    renderMenubar();
+
+    const fileMenuTrigger = screen.getByRole('menuitem', { name: 'File' });
+    const editMenuTrigger = screen.getByRole('menuitem', { name: 'Edit' });
+
+    fireEvent.click(fileMenuTrigger);
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'true');
+    expect(editMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+
+    fireEvent.click(document.body);
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+  });
+
+  it('should support top-level keyboard navigation', () => {
+    renderMenubar();
+
+    const fileMenuTrigger = screen.getByRole('menuitem', { name: 'File' });
+    const editMenuTrigger = screen.getByRole('menuitem', { name: 'Edit' });
+    fireEvent.focus(fileMenuTrigger);
+
+    fireEvent.keyDown(fileMenuTrigger, { key: 'ArrowRight' });
+    expect(editMenuTrigger).toHaveFocus();
+
+    fireEvent.keyDown(editMenuTrigger, { key: 'ArrowLeft' });
+    expect(fileMenuTrigger).toHaveFocus();
+
+    const newMenuItem = screen.getByRole('menuitem', { name: 'New' });
+
+    fireEvent.keyDown(fileMenuTrigger, { key: 'ArrowDown' });
+    expect(newMenuItem).toHaveFocus();
+
+    fireEvent.keyDown(newMenuItem, { key: 'Escape' });
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+  });
+
+  it('should support submenu keyboard navigation', () => {
+    renderMenubar();
+
+    const fileMenuTrigger = screen.getByRole('menuitem', { name: 'File' });
+    const newMenuItem = screen.getByRole('menuitem', { name: 'New' });
+    const openMenuItem = screen.getByRole('menuitem', { name: 'Open' });
+
+    const editMenuTrigger = screen.getByRole('menuitem', { name: 'Edit' });
+
+    fireEvent.click(fileMenuTrigger);
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'true');
+
+    fireEvent.keyDown(fileMenuTrigger, { key: 'ArrowDown' });
+    expect(newMenuItem).toHaveFocus();
+
+    fireEvent.keyDown(newMenuItem, { key: 'ArrowUp' });
+    expect(newMenuItem).not.toHaveFocus();
+    expect(openMenuItem).toHaveFocus();
+
+    fireEvent.keyDown(openMenuItem, { key: 'ArrowRight' });
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+    expect(openMenuItem).not.toHaveFocus();
+    expect(editMenuTrigger).toHaveFocus();
+    expect(editMenuTrigger).toHaveAttribute('aria-expanded', 'true');
+
+    fireEvent.keyDown(editMenuTrigger, { key: 'ArrowLeft' });
+    expect(editMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+    expect(editMenuTrigger).not.toHaveFocus();
+    expect(fileMenuTrigger).toHaveFocus();
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'true');
+
+    fireEvent.keyDown(newMenuItem, { key: 'Escape' });
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+  });
+
+  it('should activate a menu item when clicked', () => {
+    const handleClick = jest.fn();
+
+    render(
+      <Menubar>
+        <MenubarSubmenu id="file" title="File">
+          <MenubarItem id="file-new" title="New" onClick={handleClick}>
+            New
+          </MenubarItem>
+        </MenubarSubmenu>
+      </Menubar>
+    );
+
+    const fileMenuTrigger = screen.getByRole('menuitem', { name: 'File' });
+    const newMenuItem = screen.getByRole('menuitem', { name: 'New' });
+    fireEvent.click(fileMenuTrigger);
+    fireEvent.mouseUp(newMenuItem);
+    fireEvent.click(newMenuItem);
+
+    expect(handleClick).toHaveBeenCalled();
+    expect(fileMenuTrigger).toHaveAttribute('aria-expanded', 'false');
+  });
+
+  it('should have proper ARIA attributes', () => {
+    renderMenubar();
+
+    const menubar = screen.getByRole('menubar');
+    expect(menubar).toHaveAttribute('aria-orientation', 'horizontal');
+
+    const fileMenu = screen.getByRole('menuitem', { name: 'File' });
+    expect(fileMenu).toHaveAttribute('aria-haspopup', 'menu');
+    expect(fileMenu).toHaveAttribute('aria-expanded', 'false');
+
+    fireEvent.click(fileMenu);
+    expect(fileMenu).toHaveAttribute('aria-expanded', 'true');
+  });
+});
diff --git a/client/components/Menubar/MenubarItem.jsx b/client/components/Menubar/MenubarItem.jsx
index 8d595bb5cd..3b0aea6be9 100644
--- a/client/components/Menubar/MenubarItem.jsx
+++ b/client/components/Menubar/MenubarItem.jsx
@@ -1,46 +1,119 @@
 import PropTypes from 'prop-types';
-import React, { useContext, useMemo } from 'react';
+import React, { useEffect, useContext, useRef } from 'react';
+import { MenubarContext, SubmenuContext, ParentMenuContext } from './contexts';
 import ButtonOrLink from '../../common/ButtonOrLink';
-import { MenubarContext, ParentMenuContext } from './contexts';
+
+/**
+ * @component
+ * @param {object} props
+ * @param {string} [props.className='nav__dropdown-item'] - CSS class name to apply to the list item
+ * @param {string} props.id - The id of the list item
+ * @param {string} [props.role='menuitem'] - The role of the list item
+ * @param {boolean} [props.isDisabled=false] - Whether to hide the item
+ * @param {boolean} [props.selected=false] - Whether the item is selected
+ * @returns {JSX.Element}
+ */
+
+/**
+ * MenubarItem wraps a button or link in an accessible list item that
+ * integrates with keyboard navigation and other submenu behaviors.
+ *
+ * @example
+ * ```jsx
+ * // basic MenubarItem with click handler and keyboard shortcut
+ * <MenubarItem id="sketch-run" onClick={() => dispatch(startSketch())}>
+ *   Run
+ *   <span className="nav__keyboard-shortcut">{metaKeyName}+Enter</span>
+ * </MenubarItem>
+ *
+ * // as an option in a listbox
+ * <MenubarItem
+ *   id={key}
+ *   key={key}
+ *   value={key}
+ *   onClick={handleLangSelection}
+ *   role="option"
+ *   selected={key === language}
+ * >
+ *   {languageKeyToLabel(key)}
+ * </MenubarItem>
+ * ```
+ */
 
 function MenubarItem({
-  hideIf,
   className,
+  id,
   role: customRole,
+  isDisabled,
   selected,
   ...rest
 }) {
+  // core context and state management
+  const { createMenuItemHandlers, hasFocus } = useContext(MenubarContext);
+  const {
+    setSubmenuActiveIndex,
+    submenuItems,
+    registerSubmenuItem
+  } = useContext(SubmenuContext);
   const parent = useContext(ParentMenuContext);
 
-  const { createMenuItemHandlers } = useContext(MenubarContext);
-
-  const handlers = useMemo(() => createMenuItemHandlers(parent), [
-    createMenuItemHandlers,
-    parent
-  ]);
+  // ref for the list item
+  const menuItemRef = useRef(null);
 
-  if (hideIf) {
-    return null;
-  }
+  // handlers from parent menu
+  const handlers = createMenuItemHandlers(parent);
 
+  // role and aria-selected
   const role = customRole || 'menuitem';
   const ariaSelected = role === 'option' ? { 'aria-selected': selected } : {};
 
+  // focus submenu item on mouse enter
+  const handleMouseEnter = () => {
+    if (hasFocus) {
+      const items = Array.from(submenuItems);
+      const index = items.findIndex((item) => item === menuItemRef.current);
+      if (index !== -1) {
+        setSubmenuActiveIndex(index);
+      }
+    }
+  };
+
+  // register with parent submenu for keyboard navigation
+  useEffect(() => {
+    const unregister = registerSubmenuItem(menuItemRef);
+    return unregister;
+  }, [submenuItems, registerSubmenuItem]);
+
   return (
-    <li className={className}>
-      <ButtonOrLink {...rest} {...handlers} {...ariaSelected} role={role} />
+    <li
+      className={`${className} ${
+        isDisabled ? 'nav__dropdown-item--disabled' : ''
+      }`}
+      ref={menuItemRef}
+      onMouseEnter={handleMouseEnter}
+    >
+      <ButtonOrLink
+        {...rest}
+        {...handlers}
+        {...ariaSelected}
+        role={role}
+        tabIndex={-1}
+        id={id}
+        isDisabled={isDisabled}
+      />
     </li>
   );
 }
 
 MenubarItem.propTypes = {
   ...ButtonOrLink.propTypes,
+  id: PropTypes.string,
   onClick: PropTypes.func,
   value: PropTypes.string,
   /**
    * Provides a way to deal with optional items.
    */
-  hideIf: PropTypes.bool,
+  isDisabled: PropTypes.bool,
   className: PropTypes.string,
   role: PropTypes.oneOf(['menuitem', 'option']),
   selected: PropTypes.bool
@@ -49,9 +122,10 @@ MenubarItem.propTypes = {
 MenubarItem.defaultProps = {
   onClick: null,
   value: null,
-  hideIf: false,
+  isDisabled: false,
   className: 'nav__dropdown-item',
   role: 'menuitem',
+  id: undefined,
   selected: false
 };
 
diff --git a/client/components/Menubar/MenubarSubmenu.jsx b/client/components/Menubar/MenubarSubmenu.jsx
index 13b0e33177..c751641514 100644
--- a/client/components/Menubar/MenubarSubmenu.jsx
+++ b/client/components/Menubar/MenubarSubmenu.jsx
@@ -2,9 +2,21 @@
 
 import classNames from 'classnames';
 import PropTypes from 'prop-types';
-import React, { useContext, useMemo } from 'react';
+import React, {
+  useState,
+  useEffect,
+  useContext,
+  useCallback,
+  useRef,
+  useMemo
+} from 'react';
+import {
+  MenuOpenContext,
+  MenubarContext,
+  SubmenuContext,
+  ParentMenuContext
+} from './contexts';
 import TriangleIcon from '../../images/down-filled-triangle.svg';
-import { MenuOpenContext, MenubarContext, ParentMenuContext } from './contexts';
 
 export function useMenuProps(id) {
   const activeMenu = useContext(MenuOpenContext);
@@ -25,14 +37,101 @@ export function useMenuProps(id) {
  * MenubarTrigger
  * -----------------------------------------------------------------------------------------------*/
 
-function MenubarTrigger({ id, title, role, hasPopup, ...props }) {
+/**
+ * @component
+ * @param {Object} props
+ * @param {string} [props.role='menuitem'] - The ARIA role of the trigger button
+ * @param {string} [props.hasPopup='menu'] - The ARIA property that indicates the presence of a popup
+ * @returns {JSX.Element}
+ */
+
+/**
+ * MenubarTrigger renders a button that toggles a submenu. It handles keyboard navigations and supports
+ * screen readers. It needs to be within a submenu context.
+ *
+ * @example
+ * <li
+ *  className={classNames('nav__item', isOpen && 'nav__item--open')}
+ *  ref={listItemRef}
+ * >
+ *  <MenubarTrigger
+ *    ref={buttonRef}
+ *    role={triggerRole}
+ *    hasPopup={hasPopup}
+ *    {...handlers}
+ *    {...props}
+ *    tabIndex={-1}
+ *  />
+ *  ... menubar list
+ * </li>
+ */
+
+const MenubarTrigger = React.forwardRef(({ role, hasPopup, ...props }, ref) => {
+  const {
+    setActiveIndex,
+    menuItems,
+    registerTopLevelItem,
+    hasFocus
+  } = useContext(MenubarContext);
+  const { id, title, first, last } = useContext(SubmenuContext);
   const { isOpen, handlers } = useMenuProps(id);
 
+  // update active index when mouse enters the trigger and the menu has focus
+  const handleMouseEnter = () => {
+    if (hasFocus) {
+      const items = Array.from(menuItems);
+      const index = items.findIndex((item) => item === ref.current);
+
+      if (index !== -1) {
+        setActiveIndex(index);
+      }
+    }
+  };
+
+  // keyboard handlers
+  const handleKeyDown = (e) => {
+    switch (e.key) {
+      case 'ArrowDown':
+        if (!isOpen) {
+          e.preventDefault();
+          e.stopPropagation();
+          first();
+        }
+        break;
+      case 'ArrowUp':
+        if (!isOpen) {
+          e.preventDefault();
+          e.stopPropagation();
+          last();
+        }
+        break;
+      case 'Enter':
+      case ' ':
+        if (!isOpen) {
+          e.preventDefault();
+          e.stopPropagation();
+          first();
+        }
+        break;
+      default:
+        break;
+    }
+  };
+
+  // register trigger with parent menubar
+  useEffect(() => {
+    const unregister = registerTopLevelItem(ref, id);
+    return unregister;
+  }, [menuItems, registerTopLevelItem]);
+
   return (
     <button
-      {...handlers}
       {...props}
+      {...handlers}
+      ref={ref}
       role={role}
+      onMouseEnter={handleMouseEnter}
+      onKeyDown={handleKeyDown}
       aria-haspopup={hasPopup}
       aria-expanded={isOpen}
     >
@@ -44,11 +143,9 @@ function MenubarTrigger({ id, title, role, hasPopup, ...props }) {
       />
     </button>
   );
-}
+});
 
 MenubarTrigger.propTypes = {
-  id: PropTypes.string.isRequired,
-  title: PropTypes.node.isRequired,
   role: PropTypes.string,
   hasPopup: PropTypes.oneOf(['menu', 'listbox', 'true'])
 };
@@ -62,9 +159,33 @@ MenubarTrigger.defaultProps = {
  * MenubarList
  * -----------------------------------------------------------------------------------------------*/
 
-function MenubarList({ id, children, role, ...props }) {
+/**
+ * @component
+ * @param {Object} props
+ * @param {React.ReactNode} props.children - MenubarItems that should be rendered in the list
+ * @param {string} [props.role='menu'] - The ARIA role of the list element
+ * @returns {JSX.Element}
+ */
+
+/**
+ * MenubarList renders the container for menu items in a submenu. It provides context and handles ARIA roles.
+ *
+ * @example
+ * <MenubarList role={listRole}>
+ *  ... <MenubarItem> elements
+ * </MenubarList>
+ */
+
+function MenubarList({ children, role, ...props }) {
+  const { id, title } = useContext(SubmenuContext);
+
   return (
-    <ul className="nav__dropdown" role={role} {...props}>
+    <ul
+      className="nav__dropdown"
+      role={role}
+      aria-label={`${title} menu`}
+      {...props}
+    >
       <ParentMenuContext.Provider value={id}>
         {children}
       </ParentMenuContext.Provider>
@@ -73,7 +194,6 @@ function MenubarList({ id, children, role, ...props }) {
 }
 
 MenubarList.propTypes = {
-  id: PropTypes.string.isRequired,
   children: PropTypes.node,
   role: PropTypes.oneOf(['menu', 'listbox'])
 };
@@ -87,41 +207,281 @@ MenubarList.defaultProps = {
  * MenubarSubmenu
  * -----------------------------------------------------------------------------------------------*/
 
+/**
+ * @component
+ * @param {Object} props
+ * @param {React.ReactNode} props.children - A list of menu items that will be rendered in the menubar
+ * @param {string} props.id - The unique id of the submenu
+ * @param {string} props.title - The title of the submenu
+ * @param {string} [props.triggerRole='menuitem'] - The ARIA role of the trigger button
+ * @param {string} [props.listRole='menu'] - The ARIA role of the list element
+ * @returns {JSX.Element}
+ */
+
+/**
+ * MenubarSubmenu manages a triggerable submenu within a menubar. It is a compound component
+ * that manages the state of the submenu and its items. It also provides keyboard navigation
+ * and screen reader support. Supports menu and listbox roles. Needs to be a direct child of Menubar.
+ *
+ * @example
+ * <Menubar>
+ *  <MenubarSubmenu id="file" title="File">
+ *    <MenubarItem id="file-new" onClick={handleNew}>New</MenubarItem>
+ *    <MenubarItem id="file-save" onClick={handleSave}>Save</MenubarItem>
+ *  </MenubarSubmenu>
+ * </Menubar>
+ */
+
 function MenubarSubmenu({
+  children,
   id,
   title,
-  children,
   triggerRole: customTriggerRole,
   listRole: customListRole,
   ...props
 }) {
-  const { isOpen } = useMenuProps(id);
+  // core state for submenu management
+  const { isOpen, handlers } = useMenuProps(id);
+  const [submenuActiveIndex, setSubmenuActiveIndex] = useState(0);
+  const { setMenuOpen, toggleMenuOpen } = useContext(MenubarContext);
+  const submenuItems = useRef(new Set()).current;
 
+  // refs for the button and list elements
+  const buttonRef = useRef(null);
+  const listItemRef = useRef(null);
+
+  // roles and properties for the button and list elements
   const triggerRole = customTriggerRole || 'menuitem';
   const listRole = customListRole || 'menu';
-
   const hasPopup = listRole === 'listbox' ? 'listbox' : 'menu';
 
+  /**
+   * navigation functions for the submenu
+   */
+  const prev = useCallback(() => {
+    const newIndex =
+      submenuActiveIndex < 0
+        ? submenuItems.size - 1
+        : (submenuActiveIndex - 1 + submenuItems.size) % submenuItems.size;
+    setSubmenuActiveIndex(newIndex);
+  }, [submenuActiveIndex, submenuItems]);
+
+  const next = useCallback(() => {
+    const newIndex = (submenuActiveIndex + 1) % submenuItems.size;
+    setSubmenuActiveIndex(newIndex);
+  }, [submenuActiveIndex, submenuItems]);
+
+  const first = useCallback(() => {
+    toggleMenuOpen(id);
+
+    if (submenuItems.size > 0) {
+      setSubmenuActiveIndex(0);
+    }
+  }, [submenuItems]);
+
+  const last = useCallback(() => {
+    toggleMenuOpen(id);
+    if (submenuItems.size > 0) {
+      setSubmenuActiveIndex(submenuItems.size - 1);
+    }
+  }, [submenuItems]);
+
+  // activate the selected item
+  const activate = useCallback(() => {
+    const items = Array.from(submenuItems);
+    const activeItem = items[submenuActiveIndex]; // get the active item
+
+    if (activeItem) {
+      // since active item is a <li> element, we need to get the button or link inside it
+      const activeItemNode = activeItem.firstChild;
+
+      const isDisabled =
+        activeItemNode.getAttribute('aria-disabled') === 'true';
+
+      if (isDisabled) {
+        return;
+      }
+
+      activeItemNode.click();
+
+      toggleMenuOpen(id);
+
+      // check if buttonRef is available and focus it
+      // we check because the button might be unmounted when activating a link or button
+      if (buttonRef.current) {
+        buttonRef.current.focus();
+      }
+    }
+  }, [submenuActiveIndex, submenuItems, buttonRef]);
+
+  const close = useCallback(() => {
+    setMenuOpen('none');
+
+    if (buttonRef.current) {
+      buttonRef.current.focus();
+    }
+  }, [buttonRef]);
+
+  /**
+   * Register submenu items for keyboard navigation.
+   *
+   * @param {React.RefObject} ref - a ref to the DOM node of the menu item
+   *
+   */
+  const registerSubmenuItem = useCallback(
+    (ref) => {
+      const submenuItemNode = ref.current;
+
+      if (submenuItemNode) {
+        submenuItems.add(submenuItemNode);
+      }
+
+      return () => {
+        submenuItems.delete(submenuItemNode);
+      };
+    },
+    [submenuItems]
+  );
+
+  // key handlers for submenu navigation
+  const keyHandlers = {
+    ArrowUp: (e) => {
+      if (!isOpen) return;
+      e.preventDefault();
+      e.stopPropagation();
+      prev();
+    },
+    ArrowDown: (e) => {
+      if (!isOpen) return;
+      e.preventDefault();
+      e.stopPropagation();
+      next();
+    },
+    Enter: (e) => {
+      if (!isOpen) return;
+      e.preventDefault();
+      e.stopPropagation();
+      activate();
+    },
+    ' ': (e) => {
+      // same as Enter
+      if (!isOpen) return;
+      e.preventDefault();
+      e.stopPropagation();
+      activate();
+    },
+    Escape: (e) => {
+      if (!isOpen) return;
+      e.preventDefault();
+      e.stopPropagation();
+      close();
+    },
+    Tab: (e) => {
+      // close
+      if (!isOpen) return;
+      // e.preventDefault();
+      e.stopPropagation();
+      setMenuOpen('none');
+    }
+    // support direct access keys
+  };
+
+  // our custom keydown handler
+  const handleKeyDown = useCallback(
+    (e) => {
+      if (!isOpen) return;
+
+      const handler = keyHandlers[e.key];
+
+      if (handler) {
+        handler(e);
+      }
+    },
+    [isOpen, keyHandlers]
+  );
+
+  // reset submenu active index when submenu is closed
+  useEffect(() => {
+    if (!isOpen) {
+      setSubmenuActiveIndex(-1);
+    }
+  }, [isOpen]);
+
+  // add keydown event listener to list when submenu is open
+  useEffect(() => {
+    const el = listItemRef.current;
+    if (!el) return () => {};
+
+    el.addEventListener('keydown', handleKeyDown);
+    return () => {
+      el.removeEventListener('keydown', handleKeyDown);
+    };
+  }, [isOpen, keyHandlers]);
+
+  // focus the active item when submenu is open
+  useEffect(() => {
+    if (isOpen && submenuItems.size > 0) {
+      const items = Array.from(submenuItems);
+      const activeItem = items[submenuActiveIndex];
+
+      if (activeItem) {
+        const activeNode = activeItem.querySelector(
+          '[role="menuitem"], [role="option"]'
+        );
+        if (activeNode) {
+          activeNode.focus();
+        }
+      }
+    }
+  }, [isOpen, submenuItems, submenuActiveIndex]);
+
+  const submenuContext = useMemo(
+    () => ({
+      id,
+      title,
+      submenuItems,
+      submenuActiveIndex,
+      setSubmenuActiveIndex,
+      registerSubmenuItem,
+      first,
+      last
+    }),
+    [
+      id,
+      title,
+      submenuItems,
+      submenuActiveIndex,
+      setSubmenuActiveIndex,
+      registerSubmenuItem,
+      first,
+      last
+    ]
+  );
+
   return (
-    <li className={classNames('nav__item', isOpen && 'nav__item--open')}>
-      <MenubarTrigger
-        id={id}
-        title={title}
-        role={triggerRole}
-        hasPopup={hasPopup}
-        {...props}
-      />
-      <MenubarList id={id} role={listRole}>
-        {children}
-      </MenubarList>
-    </li>
+    <SubmenuContext.Provider value={submenuContext}>
+      <li
+        className={classNames('nav__item', isOpen && 'nav__item--open')}
+        ref={listItemRef}
+      >
+        <MenubarTrigger
+          ref={buttonRef}
+          role={triggerRole}
+          hasPopup={hasPopup}
+          {...handlers}
+          {...props}
+          tabIndex={-1}
+        />
+        <MenubarList role={listRole}>{children}</MenubarList>
+      </li>
+    </SubmenuContext.Provider>
   );
 }
 
 MenubarSubmenu.propTypes = {
   id: PropTypes.string.isRequired,
-  title: PropTypes.node.isRequired,
   children: PropTypes.node,
+  title: PropTypes.node.isRequired,
   triggerRole: PropTypes.string,
   listRole: PropTypes.string
 };
diff --git a/client/components/Menubar/contexts.jsx b/client/components/Menubar/contexts.jsx
index ab3bb9ffcf..18cad6c36b 100644
--- a/client/components/Menubar/contexts.jsx
+++ b/client/components/Menubar/contexts.jsx
@@ -9,3 +9,5 @@ export const MenubarContext = createContext({
   createMenuItemHandlers: () => ({}),
   toggleMenuOpen: () => {}
 });
+
+export const SubmenuContext = createContext({});
diff --git a/client/modules/IDE/components/Header/Nav.jsx b/client/modules/IDE/components/Header/Nav.jsx
index f40e9137bf..2ed8dd224e 100644
--- a/client/modules/IDE/components/Header/Nav.jsx
+++ b/client/modules/IDE/components/Header/Nav.jsx
@@ -39,10 +39,16 @@ const Nav = ({ layout }) => {
   ) : (
     <>
       <header className="nav__header">
-        <Menubar>
-          <LeftLayout layout={layout} />
-          <UserMenu />
-        </Menubar>
+        <div className="nav__item-logo">
+          <Logo />
+        </div>
+
+        <nav className="nav">
+          <Menubar>
+            <LeftLayout layout={layout} />
+            <UserMenu />
+          </Menubar>
+        </nav>
       </header>
     </>
   );
@@ -87,19 +93,40 @@ const UserMenu = () => {
   return null;
 };
 
-const DashboardMenu = () => {
+const Logo = () => {
   const { t } = useTranslation();
-  const editorLink = useSelector(selectSketchPath);
-  return (
-    <ul className="nav__items-left">
-      <li className="nav__item-logo">
+  const user = useSelector((state) => state.user);
+
+  if (user?.username) {
+    return (
+      <Link to={`/${user.username}/sketches`}>
         <LogoIcon
           role="img"
           aria-label={t('Common.p5logoARIA')}
           focusable="false"
           className="svg__logo"
         />
-      </li>
+      </Link>
+    );
+  }
+
+  return (
+    <a href="https://p5js.org">
+      <LogoIcon
+        role="img"
+        aria-label={t('Common.p5logoARIA')}
+        focusable="true"
+        className="svg__logo"
+      />
+    </a>
+  );
+};
+
+const DashboardMenu = () => {
+  const { t } = useTranslation();
+  const editorLink = useSelector(selectSketchPath);
+  return (
+    <ul className="nav__items-left" role="group">
       <li className="nav__item nav__item--no-icon">
         <Link to={editorLink} className="nav__back-link">
           <CaretLeftIcon
@@ -118,7 +145,7 @@ const ProjectMenu = () => {
   const isUserOwner = useSelector(getIsUserOwner);
   const project = useSelector((state) => state.project);
   const user = useSelector((state) => state.user);
-  const userSketches = `/${user.username}/sketches`;
+
   const isUnsaved = !project?.id;
 
   const rootFile = useSelector(selectRootFile);
@@ -141,33 +168,17 @@ const ProjectMenu = () => {
     metaKey === 'Ctrl' ? `${metaKeyName}+Alt+N` : `${metaKeyName}+⌥+N`;
 
   return (
-    <ul className="nav__items-left" role="menubar">
-      <li className="nav__item-logo">
-        {user && user.username !== undefined ? (
-          <Link to={userSketches}>
-            <LogoIcon
-              role="img"
-              aria-label={t('Common.p5logoARIA')}
-              focusable="false"
-              className="svg__logo"
-            />
-          </Link>
-        ) : (
-          <a href="https://p5js.org">
-            <LogoIcon
-              role="img"
-              aria-label={t('Common.p5logoARIA')}
-              focusable="false"
-              className="svg__logo"
-            />
-          </a>
-        )}
-      </li>
+    <ul className="nav__items-left" role="group">
       <MenubarSubmenu id="file" title={t('Nav.File.Title')}>
-        <MenubarItem onClick={newSketch}>{t('Nav.File.New')}</MenubarItem>
+        <MenubarItem id="file-new" onClick={newSketch}>
+          {t('Nav.File.New')}
+        </MenubarItem>
         <MenubarItem
-          hideIf={
-            !getConfig('LOGIN_ENABLED') || (project?.owner && !isUserOwner)
+          id="file-save"
+          isDisabled={
+            !user.authenticated ||
+            !getConfig('LOGIN_ENABLED') ||
+            (project?.owner && !isUserOwner)
           }
           onClick={() => saveSketch(cmRef.current)}
         >
@@ -175,25 +186,36 @@ const ProjectMenu = () => {
           <span className="nav__keyboard-shortcut">{metaKeyName}+S</span>
         </MenubarItem>
         <MenubarItem
-          hideIf={isUnsaved || !user.authenticated}
+          id="file-duplicate"
+          isDisabled={isUnsaved || !user.authenticated}
           onClick={() => dispatch(cloneProject())}
         >
           {t('Nav.File.Duplicate')}
         </MenubarItem>
-        <MenubarItem hideIf={isUnsaved} onClick={shareSketch}>
+        <MenubarItem
+          id="file-share"
+          isDisabled={isUnsaved}
+          onClick={shareSketch}
+        >
           {t('Nav.File.Share')}
         </MenubarItem>
-        <MenubarItem hideIf={isUnsaved} onClick={downloadSketch}>
+        <MenubarItem
+          id="file-download"
+          isDisabled={isUnsaved}
+          onClick={downloadSketch}
+        >
           {t('Nav.File.Download')}
         </MenubarItem>
         <MenubarItem
-          hideIf={!user.authenticated}
+          id="file-open"
+          isDisabled={!user.authenticated}
           href={`/${user.username}/sketches`}
         >
           {t('Nav.File.Open')}
         </MenubarItem>
         <MenubarItem
-          hideIf={
+          id="file-add-to-collection"
+          isDisabled={
             !getConfig('UI_COLLECTIONS_ENABLED') ||
             !user.authenticated ||
             isUnsaved
@@ -203,39 +225,46 @@ const ProjectMenu = () => {
           {t('Nav.File.AddToCollection')}
         </MenubarItem>
         <MenubarItem
-          hideIf={!getConfig('EXAMPLES_ENABLED')}
+          id="file-examples"
+          isDisabled={!getConfig('EXAMPLES_ENABLED')}
           href="/p5/sketches"
         >
           {t('Nav.File.Examples')}
         </MenubarItem>
       </MenubarSubmenu>
       <MenubarSubmenu id="edit" title={t('Nav.Edit.Title')}>
-        <MenubarItem onClick={cmRef.current?.tidyCode}>
+        <MenubarItem id="edit-tidy" onClick={cmRef.current?.tidyCode}>
           {t('Nav.Edit.TidyCode')}
           <span className="nav__keyboard-shortcut">{metaKeyName}+Shift+F</span>
         </MenubarItem>
-        <MenubarItem onClick={cmRef.current?.showFind}>
+        <MenubarItem id="edit-find" onClick={cmRef.current?.showFind}>
           {t('Nav.Edit.Find')}
           <span className="nav__keyboard-shortcut">{metaKeyName}+F</span>
         </MenubarItem>
-        <MenubarItem onClick={cmRef.current?.showReplace}>
+        <MenubarItem id="edit-replace" onClick={cmRef.current?.showReplace}>
           {t('Nav.Edit.Replace')}
           <span className="nav__keyboard-shortcut">{replaceCommand}</span>
         </MenubarItem>
       </MenubarSubmenu>
       <MenubarSubmenu id="sketch" title={t('Nav.Sketch.Title')}>
-        <MenubarItem onClick={() => dispatch(newFile(rootFile.id))}>
+        <MenubarItem
+          id="sketch-add-file"
+          onClick={() => dispatch(newFile(rootFile.id))}
+        >
           {t('Nav.Sketch.AddFile')}
           <span className="nav__keyboard-shortcut">{newFileCommand}</span>
         </MenubarItem>
-        <MenubarItem onClick={() => dispatch(newFolder(rootFile.id))}>
+        <MenubarItem
+          id="sketch-add-folder"
+          onClick={() => dispatch(newFolder(rootFile.id))}
+        >
           {t('Nav.Sketch.AddFolder')}
         </MenubarItem>
-        <MenubarItem onClick={() => dispatch(startSketch())}>
+        <MenubarItem id="sketch-run" onClick={() => dispatch(startSketch())}>
           {t('Nav.Sketch.Run')}
           <span className="nav__keyboard-shortcut">{metaKeyName}+Enter</span>
         </MenubarItem>
-        <MenubarItem onClick={() => dispatch(stopSketch())}>
+        <MenubarItem id="sketch-stop" onClick={() => dispatch(stopSketch())}>
           {t('Nav.Sketch.Stop')}
           <span className="nav__keyboard-shortcut">
             Shift+{metaKeyName}+Enter
@@ -243,13 +272,18 @@ const ProjectMenu = () => {
         </MenubarItem>
       </MenubarSubmenu>
       <MenubarSubmenu id="help" title={t('Nav.Help.Title')}>
-        <MenubarItem onClick={() => dispatch(showKeyboardShortcutModal())}>
+        <MenubarItem
+          id="help-shortcuts"
+          onClick={() => dispatch(showKeyboardShortcutModal())}
+        >
           {t('Nav.Help.KeyboardShortcuts')}
         </MenubarItem>
-        <MenubarItem href="https://p5js.org/reference/">
+        <MenubarItem id="help-reference" href="https://p5js.org/reference/">
           {t('Nav.Help.Reference')}
         </MenubarItem>
-        <MenubarItem href="/about">{t('Nav.Help.About')}</MenubarItem>
+        <MenubarItem id="help-about" href="/about">
+          {t('Nav.Help.About')}
+        </MenubarItem>
       </MenubarSubmenu>
       {getConfig('TRANSLATIONS_ENABLED') && <LanguageMenu />}
     </ul>
@@ -275,6 +309,7 @@ const LanguageMenu = () => {
       {sortBy(availableLanguages).map((key) => (
         // eslint-disable-next-line react/jsx-no-bind
         <MenubarItem
+          id={key}
           key={key}
           value={key}
           onClick={handleLangSelection}
@@ -291,7 +326,7 @@ const LanguageMenu = () => {
 const UnauthenticatedUserMenu = () => {
   const { t } = useTranslation();
   return (
-    <ul className="nav__items-right" title="user-menu">
+    <ul className="nav__items-right" title="user-menu" role="group">
       <li className="nav__item">
         <Link to="/login" className="nav__auth-button">
           <span className="nav__item-header" title="Login">
@@ -320,7 +355,7 @@ const AuthenticatedUserMenu = () => {
   const dispatch = useDispatch();
 
   return (
-    <ul className="nav__items-right" title="user-menu">
+    <ul className="nav__items-right" title="user-menu" role="group">
       <MenubarSubmenu
         id="account"
         title={
@@ -329,20 +364,23 @@ const AuthenticatedUserMenu = () => {
           </span>
         }
       >
-        <MenubarItem href={`/${username}/sketches`}>
+        <MenubarItem id="account-sketches" href={`/${username}/sketches`}>
           {t('Nav.Auth.MySketches')}
         </MenubarItem>
         <MenubarItem
+          id="account-collections"
           href={`/${username}/collections`}
-          hideIf={!getConfig('UI_COLLECTIONS_ENABLED')}
+          isDisabled={!getConfig('UI_COLLECTIONS_ENABLED')}
         >
           {t('Nav.Auth.MyCollections')}
         </MenubarItem>
-        <MenubarItem href={`/${username}/assets`}>
+        <MenubarItem id="account-assets" href={`/${username}/assets`}>
           {t('Nav.Auth.MyAssets')}
         </MenubarItem>
-        <MenubarItem href="/account">{t('Preferences.Settings')}</MenubarItem>
-        <MenubarItem onClick={() => dispatch(logoutUser())}>
+        <MenubarItem id="account-settings" href="/account">
+          {t('Preferences.Settings')}
+        </MenubarItem>
+        <MenubarItem id="account-logout" onClick={() => dispatch(logoutUser())}>
           {t('Nav.Auth.LogOut')}
         </MenubarItem>
       </MenubarSubmenu>
diff --git a/client/modules/IDE/components/Header/Nav.unit.test.jsx b/client/modules/IDE/components/Header/Nav.unit.test.jsx
index 4ee6b8dae1..a15df02f4f 100644
--- a/client/modules/IDE/components/Header/Nav.unit.test.jsx
+++ b/client/modules/IDE/components/Header/Nav.unit.test.jsx
@@ -1,3 +1,4 @@
+/* eslint-disable react/prop-types */
 import React from 'react';
 import { reduxRender } from '../../../../test-utils';
 
@@ -5,6 +6,51 @@ import Nav from './Nav';
 
 jest.mock('../../../../utils/generateRandomName');
 
+// mock Menubar
+jest.mock(
+  '../../../../components/Menubar/Menubar',
+  () =>
+    function Menubar({ children, className = 'nav__menubar' }) {
+      return (
+        <ul className={className} role="menubar">
+          {children}
+        </ul>
+      );
+    }
+);
+
+// mock MenubarSubmenu
+jest.mock('../../../../components/Menubar/MenubarSubmenu', () => {
+  function MenubarSubmenu({ children, title }) {
+    return (
+      <li className="nav__item">
+        <span role="menuitem">{title}</span>
+        <ul role="menu" aria-label={`${title} menu`}>
+          {children}
+        </ul>
+      </li>
+    );
+  }
+
+  MenubarSubmenu.useMenuProps = () => ({
+    isOpen: false,
+    handlers: {}
+  });
+
+  return MenubarSubmenu;
+});
+
+// mock MenubarItem
+jest.mock(
+  '../../../../components/Menubar/MenubarItem',
+  () =>
+    function MenubarItem({ children, hideIf }) {
+      if (hideIf) return null;
+
+      return <li>{children}</li>;
+    }
+);
+
 describe('Nav', () => {
   it('renders editor version for desktop', () => {
     const { asFragment } = reduxRender(<Nav />, { mobile: false });
diff --git a/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap b/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap
index 290528582a..faa260aa8b 100644
--- a/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap
+++ b/client/modules/IDE/components/Header/__snapshots__/Nav.unit.test.jsx.snap
@@ -6,42 +6,52 @@ exports[`Nav renders dashboard version for desktop 1`] = `
     class="nav__header"
   >
     <div
+      class="nav__item-logo"
+    >
+      <a
+        href="https://p5js.org"
+      >
+        <test-file-stub
+          aria-label="p5.js Logo"
+          classname="svg__logo"
+          focusable="true"
+          role="img"
+        />
+      </a>
+    </div>
+    <nav
       class="nav"
     >
       <ul
-        class="nav__items-left"
+        class="nav__menubar"
+        role="menubar"
       >
-        <li
-          class="nav__item-logo"
-        >
-          <test-file-stub
-            aria-label="p5.js Logo"
-            classname="svg__logo"
-            focusable="false"
-            role="img"
-          />
-        </li>
-        <li
-          class="nav__item nav__item--no-icon"
+        <ul
+          class="nav__items-left"
+          role="group"
         >
-          <a
-            class="nav__back-link"
-            href="/"
+          <li
+            class="nav__item nav__item--no-icon"
           >
-            <test-file-stub
-              aria-hidden="true"
-              classname="nav__back-icon"
-              focusable="false"
-            />
-            <span
-              class="nav__item-header"
-            >
-              Back to Editor
-            </span>
-          </a>
-        </li>
+            <a
+              class="nav__back-link"
+              href="/"
+            >
+              <test-file-stub
+                aria-hidden="true"
+                classname="nav__back-icon"
+                focusable="false"
+              />
+              <span
+                class="nav__item-header"
+              >
+                Back to Editor
+              </span>
+            </a>
+          </li>
+        </ul>
       </ul>
-    </div>
+    </nav>
   </header>
 </DocumentFragment>
 `;
@@ -267,8 +277,9 @@ exports[`Nav renders dashboard version for mobile 1`] = `
   color: #FFF;
 }
 
-<div
+<ul
     class="c0"
+    role="menubar"
   >
     <div
       class="c1"
@@ -350,135 +361,58 @@ exports[`Nav renders dashboard version for mobile 1`] = `
           <b>
             File
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              New
-            </button>
+          <li>
+            New
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Save
-            </button>
+          <li>
+            Save
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="/p5/sketches"
-              role="menuitem"
-            >
-              Examples
-            </a>
+          <li>
+            Examples
           </li>
           <b>
             Edit
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Tidy Code
-            </button>
+          <li>
+            Tidy Code
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Find
-            </button>
+          <li>
+            Find
           </li>
           <b>
             Sketch
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Add File
-            </button>
+          <li>
+            Add File
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Add Folder
-            </button>
+          <li>
+            Add Folder
           </li>
           <b>
             Settings
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Preferences
-            </button>
+          <li>
+            Preferences
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Language
-            </button>
+          <li>
+            Language
           </li>
           <b>
             Help
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Keyboard Shortcuts
-            </button>
+          <li>
+            Keyboard Shortcuts
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="https://p5js.org/reference/"
-              rel="noopener noreferrer"
-              role="menuitem"
-              target="_blank"
-            >
-              Reference
-            </a>
+          <li>
+            Reference
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="/about"
-              role="menuitem"
-            >
-              About
-            </a>
+          <li>
+            About
           </li>
         </ul>
       </div>
     </div>
-  </div>
+  </ul>
 </DocumentFragment>
 `;
 
@@ -488,261 +422,178 @@ exports[`Nav renders editor version for desktop 1`] = `
     class="nav__header"
   >
     <div
+      class="nav__item-logo"
+    >
+      <a
+        href="https://p5js.org"
+      >
+        <test-file-stub
+          aria-label="p5.js Logo"
+          classname="svg__logo"
+          focusable="true"
+          role="img"
+        />
+      </a>
+    </div>
+    <nav
       class="nav"
     >
       <ul
-        class="nav__items-left"
+        class="nav__menubar"
         role="menubar"
       >
-        <li
-          class="nav__item-logo"
-        >
-          <a
-            href="https://p5js.org"
-          >
-            <test-file-stub
-              aria-label="p5.js Logo"
-              classname="svg__logo"
-              focusable="false"
-              role="img"
-            />
-          </a>
-        </li>
-        <li
-          class="nav__item"
+        <ul
+          class="nav__items-left"
+          role="group"
         >
-          <button
-            aria-expanded="false"
-            aria-haspopup="menu"
-            role="menuitem"
+          <li
+            class="nav__item"
           >
             <span
-              class="nav__item-header"
+              role="menuitem"
             >
               File
             </span>
-            <test-file-stub
-              aria-hidden="true"
-              classname="nav__item-header-triangle"
-              focusable="false"
-            />
-          </button>
-          <ul
-            class="nav__dropdown"
-            role="menu"
-          >
-            <li
-              class="nav__dropdown-item"
+            <ul
+              aria-label="File menu"
+              role="menu"
             >
-              <button
-                role="menuitem"
-              >
+              <li>
                 New
-              </button>
-            </li>
-          </ul>
-        </li>
-        <li
-          class="nav__item"
-        >
-          <button
-            aria-expanded="false"
-            aria-haspopup="menu"
-            role="menuitem"
+              </li>
+              <li>
+                Save
+                <span
+                  class="nav__keyboard-shortcut"
+                >
+                  Ctrl+S
+                </span>
+              </li>
+              <li>
+                Duplicate
+              </li>
+              <li>
+                Share
+              </li>
+              <li>
+                Download
+              </li>
+              <li>
+                Open
+              </li>
+              <li>
+                Add to Collection
+              </li>
+              <li>
+                Examples
+              </li>
+            </ul>
+          </li>
+          <li
+            class="nav__item"
           >
             <span
-              class="nav__item-header"
+              role="menuitem"
             >
               Edit
             </span>
-            <test-file-stub
-              aria-hidden="true"
-              classname="nav__item-header-triangle"
-              focusable="false"
-            />
-          </button>
-          <ul
-            class="nav__dropdown"
-            role="menu"
-          >
-            <li
-              class="nav__dropdown-item"
+            <ul
+              aria-label="Edit menu"
+              role="menu"
             >
-              <button
-                role="menuitem"
-              >
+              <li>
                 Tidy Code
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Ctrl+Shift+F
                 </span>
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <button
-                role="menuitem"
-              >
+              </li>
+              <li>
                 Find
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Ctrl+F
                 </span>
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <button
-                role="menuitem"
-              >
+              </li>
+              <li>
                 Replace
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Ctrl+H
                 </span>
-              </button>
-            </li>
-          </ul>
-        </li>
-        <li
-          class="nav__item"
-        >
-          <button
-            aria-expanded="false"
-            aria-haspopup="menu"
-            role="menuitem"
+              </li>
+            </ul>
+          </li>
+          <li
+            class="nav__item"
           >
             <span
-              class="nav__item-header"
+              role="menuitem"
             >
               Sketch
             </span>
-            <test-file-stub
-              aria-hidden="true"
-              classname="nav__item-header-triangle"
-              focusable="false"
-            />
-          </button>
-          <ul
-            class="nav__dropdown"
-            role="menu"
-          >
-            <li
-              class="nav__dropdown-item"
+            <ul
+              aria-label="Sketch menu"
+              role="menu"
             >
-              <button
-                role="menuitem"
-              >
+              <li>
                 Add File
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Ctrl+Alt+N
                 </span>
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <button
-                role="menuitem"
-              >
+              </li>
+              <li>
                 Add Folder
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <button
-                role="menuitem"
-              >
+              </li>
+              <li>
                 Run
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Ctrl+Enter
                 </span>
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <button
-                role="menuitem"
-              >
+              </li>
+              <li>
                 Stop
                 <span
                   class="nav__keyboard-shortcut"
                 >
                   Shift+Ctrl+Enter
                 </span>
-              </button>
-            </li>
-          </ul>
-        </li>
-        <li
-          class="nav__item"
-        >
-          <button
-            aria-expanded="false"
-            aria-haspopup="menu"
-            role="menuitem"
+              </li>
+            </ul>
+          </li>
+          <li
+            class="nav__item"
           >
             <span
-              class="nav__item-header"
+              role="menuitem"
             >
               Help
             </span>
-            <test-file-stub
-              aria-hidden="true"
-              classname="nav__item-header-triangle"
-              focusable="false"
-            />
-          </button>
-          <ul
-            class="nav__dropdown"
-            role="menu"
-          >
-            <li
-              class="nav__dropdown-item"
+            <ul
+              aria-label="Help menu"
+              role="menu"
             >
-              <button
-                role="menuitem"
-              >
+              <li>
                 Keyboard Shortcuts
-              </button>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <a
-                href="https://p5js.org/reference/"
-                rel="noopener noreferrer"
-                role="menuitem"
-                target="_blank"
-              >
+              </li>
+              <li>
                 Reference
-              </a>
-            </li>
-            <li
-              class="nav__dropdown-item"
-            >
-              <a
-                href="/about"
-                role="menuitem"
-              >
+              </li>
+              <li>
                 About
-              </a>
-            </li>
-          </ul>
-        </li>
+              </li>
+            </ul>
+          </li>
+        </ul>
       </ul>
-    </div>
+    </nav>
   </header>
 </DocumentFragment>
 `;
@@ -968,8 +819,9 @@ exports[`Nav renders editor version for mobile 1`] = `
   color: #FFF;
 }
 
-<div
+<ul
     class="c0"
+    role="menubar"
   >
     <div
       class="c1"
@@ -1051,134 +903,57 @@ exports[`Nav renders editor version for mobile 1`] = `
           <b>
             File
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              New
-            </button>
+          <li>
+            New
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Save
-            </button>
+          <li>
+            Save
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="/p5/sketches"
-              role="menuitem"
-            >
-              Examples
-            </a>
+          <li>
+            Examples
           </li>
           <b>
             Edit
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Tidy Code
-            </button>
+          <li>
+            Tidy Code
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Find
-            </button>
+          <li>
+            Find
           </li>
           <b>
             Sketch
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Add File
-            </button>
+          <li>
+            Add File
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Add Folder
-            </button>
+          <li>
+            Add Folder
           </li>
           <b>
             Settings
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Preferences
-            </button>
+          <li>
+            Preferences
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Language
-            </button>
+          <li>
+            Language
           </li>
           <b>
             Help
           </b>
-          <li
-            class="nav__dropdown-item"
-          >
-            <button
-              role="menuitem"
-            >
-              Keyboard Shortcuts
-            </button>
+          <li>
+            Keyboard Shortcuts
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="https://p5js.org/reference/"
-              rel="noopener noreferrer"
-              role="menuitem"
-              target="_blank"
-            >
-              Reference
-            </a>
+          <li>
+            Reference
           </li>
-          <li
-            class="nav__dropdown-item"
-          >
-            <a
-              href="/about"
-              role="menuitem"
-            >
-              About
-            </a>
+          <li>
+            About
           </li>
         </ul>
       </div>
     </div>
-  </div>
+  </ul>
 </DocumentFragment>
 `;
diff --git a/client/styles/components/_nav.scss b/client/styles/components/_nav.scss
index 58691ff251..5d597596ac 100644
--- a/client/styles/components/_nav.scss
+++ b/client/styles/components/_nav.scss
@@ -24,6 +24,13 @@
   // padding-left: #{math.div(20, $base-font-size)}rem;
 }
 
+.nav__menubar {
+  display: flex;
+  flex-direction: row;
+  width:100%;
+  justify-content: space-between;
+}
+
 .nav__items-left,
 .nav__items-right {
   list-style: none;
@@ -37,15 +44,6 @@
   @include icon();
 }
 
-// .nav__items-left,
-// .nav__items-right {
-//   & button, & a {
-//     @include themify() {
-//       color: getThemifyVariable('primary-text-color');
-//     }
-//   }
-// }
-
 .nav__item {
   position: relative;
   display: flex;
@@ -58,6 +56,60 @@
   }
 }
 
+// base focus styles
+.nav__item button:focus {  
+  @include themify() {
+    background-color: getThemifyVariable('nav-hover-color');
+  }
+  
+  .nav__item-header {
+    @include themify() {
+      color: getThemifyVariable('button-hover-color');
+    }
+  }
+
+  .nav__item-header-triangle polygon,
+  .nav__item-header-triangle path {
+    @include themify() {
+      fill: getThemifyVariable('button-hover-color');
+    }
+  }  
+}
+
+
+.nav__dropdown-item {
+  & button:focus,
+  & a:focus {
+    @include themify() {
+      color: getThemifyVariable('button-hover-color');
+      background-color: getThemifyVariable('nav-hover-color');
+    }
+  }
+  & button:focus .nav__keyboard-shortcut,
+  & a:focus .nav__keyboard-shortcut {
+    @include themify() {
+      color: getThemifyVariable('button-hover-color');
+    }
+  }
+
+  &.nav__dropdown-item--disabled {
+    & button,
+    & a,
+    & button:hover,
+    & a:hover {
+      @include themify() {
+        color: getThemifyVariable('button-nav-inactive-color');
+      }
+
+      & .nav__keyboard-shortcut {
+        @include themify() {
+          color: getThemifyVariable('button-nav-inactive-color');
+        }
+      }
+    }
+  }
+}
+
 .nav__item--no-icon {
   padding-left: #{math.div(15, $base-font-size)}rem;
 }
@@ -70,9 +122,13 @@
 }
 
 .nav__item:hover {
+  @include themify() {
+    background-color: getThemifyVariable('nav-hover-color');
+  }
+
   .nav__item-header {
     @include themify() {
-      color: getThemifyVariable('nav-hover-color');
+      color: getThemifyVariable('button-hover-color');
     }
   }
   
@@ -85,7 +141,7 @@
   .nav__item-header-triangle polygon,
   .nav__item-header-triangle path {
     @include themify() {
-      fill: getThemifyVariable('nav-hover-color');
+      fill: getThemifyVariable('button-hover-color');
     }
   }
 }