JSFiddle - React, Tailwind, and code Playground

by raviteja gunda

HTML

<nav>
        <ul class="menu">
            <li><a href="#">Home</a></li>
            <li class="has-submenu">
                <button aria-haspopup="true" aria-expanded="false">About</button>
                <ul class="submenu">
                    <li><a href="#">Our Team</a></li>
                    <li class="has-submenu">
                        <button aria-haspopup="true" aria-expanded="false">Our History</button>
                        <ul class="submenu">
                            <li><a href="#">History 1</a></li>
                            <li><a href="#">History 2</a></li>
                            <li><a href="#">History 3</a></li>
                        </ul>
                    </li>
                    <li><a href="#">Mission & Values</a></li>
                </ul>
            </li>
            <li><a href="#">Services</a></li>
            <li class="has-submenu">
                <button aria-haspopup="true" aria-expanded="false">Contact</button>
                <ul class="submenu">
                    <li><a href="#">Email Us</a></li>
                    <li><a href="#">Visit Us</a></li>
                </ul>
            </li>
        </ul>
    </nav>

CSS

body {
    font-family: Arial, sans-serif;
}

.menu {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
}

.menu > li {
    position: relative;
    margin-right: 1em;
}

.menu > li > a,
.menu > li > button {
    text-decoration: none;
    padding: 1em;
    display: block;
    color: #333;
    background-color: #f0f0f0;
    border: none;
    cursor: pointer;
    text-align: left;
    width: 100%;
}

.menu > li > a:focus,
.menu > li > button:focus {
    background-color: #ccc;
}

.submenu {
    list-style: none;
    padding: 0;
    margin: 0;
    position: absolute;
    top: 100%;
    left: 0;
    display: none;
    background-color: #f0f0f0;
}

.submenu li {
    position: relative;
}

.submenu li a,
.submenu li button {
    text-decoration: none;
    padding: 1em;
    display: block;
    color: #333;
    border: none;
    cursor: pointer;
}

.submenu li a:focus,
.submenu li button:focus {
    background-color: #ccc;
}

.submenu .submenu {
    top: 0;
    left: 100%;
}

.menu .has-submenu[aria-expanded="true"] > .submenu {
    display: block;
}

JavaScript

document.addEventListener('DOMContentLoaded', function () {
    const menuItems = document.querySelectorAll('.has-submenu > button');

    menuItems.forEach(item => {
        item.addEventListener('click', function (event) {
            event.preventDefault();

            // Close all other submenus that are not in the same hierarchy
            menuItems.forEach(otherItem => {
                const otherSubmenu = otherItem.closest('.submenu');
                const currentSubmenu = item.closest('.submenu');

                if (otherItem !== item && (!otherSubmenu || otherSubmenu !== currentSubmenu)) {
                    otherItem.setAttribute('aria-expanded', 'false');
                    otherItem.nextElementSibling.style.display = 'none';
                }
            });

            // Toggle the clicked submenu
            const isExpanded = this.getAttribute('aria-expanded') === 'true';
            this.setAttribute('aria-expanded', !isExpanded);
            const submenu = this.nextElementSibling;
            submenu.style.display = !isExpanded ? 'block' : 'none';
        });

        item.addEventListener('keydown', function (event) {
            const submenuLinks = this.nextElementSibling.querySelectorAll('a, button');
            const submenuFirstLink = submenuLinks[0];
            const submenuLastLink = submenuLinks[submenuLinks.length - 1];

            if (event.key === 'Tab' && this.getAttribute('aria-expanded') === 'true') {
                if (event.shiftKey) {
                    if (document.activeElement === this) {
                        submenuLastLink.focus();
                        event.preventDefault();
                    } else if (document.activeElement === submenuFirstLink) {
                        this.focus();
                        event.preventDefault();
                    }
                } else {
                    if (document.activeElement === this) {
                        submenuFirstLink.focus();
            ...