Following the below tutorial I can see how to use a Tailwind navbar to code a menu, with a single sub-menu: https://webcrunch.com/posts/code-a-mega-menu-with-tailwind-css
Link to example via CodePen below: https://codepen.io/webcrunchblog/pen/MWxGMdR?editors=1010
Code snippet:
document.addEventListener("DOMContentLoaded", () => {
// Select all dropdown toggle buttons
const dropdownToggles = document.querySelectorAll(".dropdown-toggle")
dropdownToggles.forEach((toggle) => {
toggle.addEventListener("click", () => {
// Find the next sibling element which is the dropdown menu
const dropdownMenu = toggle.nextElementSibling
// Toggle the 'hidden' class to show or hide the dropdown menu
if (dropdownMenu.classList.contains("hidden")) {
// Hide any open dropdown menus before showing the new one
document.querySelectorAll(".dropdown-menu").forEach((menu) => {
menu.classList.add("hidden")
})
dropdownMenu.classList.remove("hidden")
} else {
dropdownMenu.classList.add("hidden")
}
})
})
// Clicking outside of an open dropdown menu closes it
window.addEventListener("click", function (e) {
if (!e.target.matches(".dropdown-toggle")) {
document.querySelectorAll(".dropdown-menu").forEach((menu) => {
if (!menu.contains(e.target)) {
menu.classList.add("hidden")
}
})
}
})
// Mobile menu toggle
const mobileMenuButton = document.querySelector('.mobile-menu-button')
const mobileMenu = document.querySelector('.navigation-menu')
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden')
})
})
<script src="https://cdn.tailwindcss.com"></script>
ā<nav class="bg-sky-600 text-white">
<div class="container mx-auto px-4 md:flex items-center gap-6">
<!-- Logo -->
<div class="flex items-center justify-between md:w-auto w-full">
<a href="#" class="py-5 px-2 text-white flex-1 font-bold">Webcrunch.com</a>
<!-- mobile menu icon -->
<div class="md:hidden flex items-center">
<button type="button" class="mobile-menu-button">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12" />
</svg>
</button>
</div>
</div>
<div class="hidden md:flex md:flex-row flex-col items-center justify-start md:space-x-1 pb-3 md:pb-0 navigation-menu">
<a href="#" class="py-2 px-3 block">Home</a>
<a href="#" class="py-2 px-3 block">About</a>
<!-- Dropdown menu -->
<div class="relative">
<button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
<span class="pointer-events-none select-none">Services</span>
<svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Design</a>
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Development</a>
<a href="#" class="block px-6 py-2 hover:bg-sky-800">SEO</a>
<!-- Dropdown menu -->
<div class="relative">
<button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
<span class="pointer-events-none select-none">Test</span>
<svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Nested sub menu item</a>
</div>
</div>
</div>
</div>
<a href="#" class="py-2 px-3 block">Contact</a>
</div>
</div>
</nav>
How can I modify this code to create a nested sub-menu. For example, trigger an additional sub-menu when clicking on a link within the existing sub-menu.
Attempts to do this by modifying the HTML results in the mainsub-menu closing when trying to trigger the nested sub-menu.
First of all, you have two attributes class on the two last svg elements.
Next, you need to close dropdowns if, and only if, they are not ancestors of the action button.
I've added a little of css with tailwind to beautify your tets button.
document.addEventListener("DOMContentLoaded", () => {
// Select all dropdown toggle buttons
const dropdownToggles = document.querySelectorAll(".dropdown-toggle")
dropdownToggles.forEach((toggle) => {
toggle.addEventListener("click", () => {
// Find the next sibling element which is the dropdown menu
const dropdownMenu = toggle.nextElementSibling
// Toggle the 'hidden' class to show or hide the dropdown menu
if (dropdownMenu.classList.contains("hidden")) {
// Hide dropdown menus which are not ancestor of toggle before showing the new one
document.querySelectorAll(".dropdown-menu").forEach((menu) => {
if (!menu.contains(toggle)) {
menu.classList.add("hidden")
}
})
dropdownMenu.classList.remove("hidden")
} else {
dropdownMenu.classList.add("hidden")
}
})
})
// Clicking outside of an open dropdown menu closes it
window.addEventListener("click", function (e) {
if (!e.target.matches(".dropdown-toggle")) {
document.querySelectorAll(".dropdown-menu").forEach((menu) => {
if (!menu.contains(e.target)) {
menu.classList.add("hidden")
}
})
}
})
// Mobile menu toggle
const mobileMenuButton = document.querySelector('.mobile-menu-button')
const mobileMenu = document.querySelector('.navigation-menu')
mobileMenuButton.addEventListener('click', () => {
mobileMenu.classList.toggle('hidden')
})
})
<script src="https://cdn.tailwindcss.com"></script>
<nav class="bg-sky-600 text-white">
<div class="container mx-auto px-4 md:flex items-center gap-6">
<!-- Logo -->
<div class="flex items-center justify-between md:w-auto w-full">
<a href="#" class="py-5 px-2 text-white flex-1 font-bold">Webcrunch.com</a>
<!-- mobile menu icon -->
<div class="md:hidden flex items-center">
<button type="button" class="mobile-menu-button">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12" />
</svg>
</button>
</div>
</div>
<div class="hidden md:flex md:flex-row flex-col items-center justify-start md:space-x-1 pb-3 md:pb-0 navigation-menu">
<a href="#" class="py-2 px-3 block">Home</a>
<a href="#" class="py-2 px-3 block">About</a>
<!-- Dropdown menu -->
<div class="relative">
<button type="button" class="dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
<span class="pointer-events-none select-none">Services</span>
<svg class="w-6 h-6 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Design</a>
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Web Development</a>
<a href="#" class="block px-6 py-2 hover:bg-sky-800">SEO</a>
<!-- Dropdown menu -->
<div class="relative">
<button type="button" class="flex px-6 py-2 w-full justify-between dropdown-toggle py-2 px-3 hover:bg-sky-800 flex items-center gap-2 rounded">
<span class="pointer-events-none select-none">Test</span>
<svg class="w-3 h-3 pointer-events-none" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<div class="dropdown-menu absolute hidden bg-sky-700 text-white rounded-b-lg pb-2 w-48">
<a href="#" class="block px-6 py-2 hover:bg-sky-800">Nested sub menu item</a>
</div>
</div>
</div>
</div>
<a href="#" class="py-2 px-3 block">Contact</a>
</div>
</div>
</nav>
Let me know if it doesn't suit you.