Hone logo
Hone
Problems

React Nested Dropdown Menu Challenge

Develop a reusable and accessible nested dropdown menu component in React using TypeScript. This component will allow users to navigate through hierarchical menu structures, providing a dynamic and user-friendly navigation experience, essential for complex application interfaces and site maps.

Problem Description

Your task is to create a NestedDropdown component that can render menus with multiple levels of nesting. The component should accept a data structure representing the menu items and their hierarchical relationships.

Key Requirements:

  1. Hierarchical Rendering: The component must correctly render parent menu items that, when clicked or hovered over, reveal their child sub-menus.
  2. Data Structure: The component should accept an array of menu item objects. Each object should have at least:
    • id: A unique identifier for the menu item.
    • label: The text to display for the menu item.
    • children: An optional array of child menu item objects, forming the nested structure.
  3. Interactivity:
    • Parent menu items should visually indicate that they have sub-menus (e.g., with an arrow icon).
    • Sub-menus should be displayed upon user interaction (e.g., hover or click).
    • Clicking a leaf (non-parent) menu item should trigger an onItemClick callback with the clicked item's data.
  4. Accessibility: The component should be built with accessibility in mind, using appropriate ARIA attributes and keyboard navigation support.
  5. Styling: Basic styling should be provided, and the component should be designed to be easily themeable.
  6. Reusability: The NestedDropdown component should be generic enough to work with various data structures as long as they conform to the specified format.

Expected Behavior:

  • When the application loads, only the top-level menu items should be visible.
  • Hovering over or clicking a parent menu item should reveal its immediate children.
  • If a child menu item is also a parent, hovering or clicking it should reveal its children, and so on.
  • Clicking a menu item without children should execute the onItemClick function, passing the selected item's data.
  • Sub-menus should close when the user clicks outside of the menu or navigates away.

Edge Cases:

  • Empty menu data.
  • Menus with only one level of nesting.
  • Deeply nested menus.
  • Menu items with very long labels.

Examples

Example 1: Basic Nested Menu

Input Data:
[
  {
    id: '1',
    label: 'File',
    children: [
      { id: '1-1', label: 'New' },
      { id: '1-2', label: 'Open', children: [
        { id: '1-2-1', label: 'Recent Files' },
        { id: '1-2-2', label: 'Browse...' }
      ]},
      { id: '1-3', label: 'Save' }
    ]
  },
  {
    id: '2',
    label: 'Edit',
    children: [
      { id: '2-1', label: 'Cut' },
      { id: '2-2', label: 'Copy' },
      { id: '2-3', label: 'Paste' }
    ]
  }
]

OnItemClick Callback:
A function that receives an object like { id: string, label: string }

Expected Behavior:
- Clicking 'File' reveals 'New', 'Open', 'Save'.
- Hovering/Clicking 'Open' reveals 'Recent Files', 'Browse...'.
- Clicking 'New' or 'Save' triggers onItemClick('File', 'New') or onItemClick('File', 'Save').
- Clicking 'Recent Files' or 'Browse...' triggers onItemClick('File', 'Open', 'Recent Files') or onItemClick('File', 'Open', 'Browse...').

Example 2: Single Level Menu

Input Data:
[
  { id: 'A', label: 'Option A' },
  { id: 'B', label: 'Option B' }
]

OnItemClick Callback:
A function that receives an object like { id: string, label: string }

Expected Behavior:
- Only 'Option A' and 'Option B' are visible.
- Clicking 'Option A' triggers onItemClick('A', 'Option A').

Example 3: Empty Menu Data

Input Data:
[]

Expected Behavior:
- The component renders nothing or a placeholder message indicating an empty menu.

Constraints

  • The menu data structure will always be an array of objects.
  • Each menu item object will have a string id and a string label.
  • The children property, if present, will be an array of menu item objects conforming to the same structure.
  • The component should be performant even with deeply nested menus (up to 10 levels deep).
  • The onItemClick callback should be invoked only for menu items that do not have children (leaf nodes).

Notes

  • Consider how you will manage the state of which sub-menus are currently open.
  • Think about using CSS for positioning and visual cues (like arrows).
  • For accessibility, consider using aria-haspopup, aria-expanded, and appropriate keyboard event handling (e.g., Tab, Enter, ArrowKeys).
  • You can define your own interface for the menu item data structure.
  • The implementation should ideally avoid external libraries for dropdown logic, focusing on core React and TypeScript.
Loading editor...
typescript