August 3, 2022
•Last updated November 5, 2023
Code a mega menu with Tailwind CSS
If you are an avid Tailwind CSS user like myself, you probably landed here to learn how to make better use of Tailwind CSS for a more complex solution like a mega navigation menu.
I was inspired by Stripe's navigation, so part of this guide is stealing some inspiration from them. We'll need to leverage Tailwind CSS to make this all work, as well as some JavaScript.
To make my and your life easier, I'm reaching for the Vite JS. Think of Vite as a progressive front-end stack ready to use and less complex than something like Webpack. I'll often use this on static sites just or more front-end-focused apps.
Installing Vite
You can skip Vite if you don't want the additional baggage of the tooling under the hood, but for the sake of being thorough, I include the installation steps and configuration in this guide.
I'd recommend reading through the Vite guide if you are brand new to it.
Installation is pretty straightforward. I use Yarn for a node package manager, but npm works just as well if you prefer it.
The following code should present some prompts as you configure the app. I'll be using vanilla
JavaScript in this guide. Be sure to select those if you are following along.
I called my project tailwind-mega-nav
but feel free to name it what you wish.
yarn create vite
When the project gets created, you need to cd
into the root folder of the project and run yarn.
Installing Tailwind CSS
With Vite installed, we'll install Tailwind CSS next. Doing so takes a few steps, but it's pretty simple. There's a handy guide on tailwindcss.com for installing with Vite, but it's geared toward Vue.js users, so I'll do things slightly differently.
yarn add tailwindcss postcss autoprefixer -D
yarn tailwindcss init -p
The two lines above should install Tailwind CSS and its dependencies and also create a PostCSS configuration file and a Tailwind CSS configuration file at the root of your project.
I'll extend the tailwind.config.cjs
file slightly to look like the following:
// tailwind.config.js
module.exports = {
content: ["./index.html", "*.js"],
theme: {
extend: {},
},
plugins: [],
}
The array passed in the content
option tells Tailwind where all our template files will be if you increase pages or file types; you probably need to adjust this.
Adding CSS
Next, we need to remove the default code from Vite. I removed all the contents of style.css
and replaced it with the following.
/* style.css */
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
Next, remove the code from main.js
and replace it with the following:
// main.js
import "./style.css"
Then finally, delete the javascript.svg
file and counter.js
file from the root folder.
Boot up the server
To preview everything, you can run the simple command below.
yarn dev
This command should boot up a local server at http://127.0.0.1:5173/
I updated the index.html
file in the root of the project to look like the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tailwind CSS Mega Nav</title>
</head>
<body>
<h1 class="text-indigo-600 font-bold text-3xl">Hello World</h1>
<script type="module" src="/main.js"></script>
</body>
</html>
If you see a larger heading with an indigo color, it works!
Scaffolding the navigation
In this part, I'll save you the trouble and add all the markup we'll use below without any Tailwind CSS classes. As we start styling, I'll leverage several classes to make the menu work as expected. This menu is quite extensive hence the mega
naming convention.
Add the following between the body
tags.
<header>
<a href="#">Pipe</a>
<nav>
<ul>
<li>
<button>Products</button>
<div>
<ul>
<li>
<a href="#">
Course Editor
<p>All in one editor</p>
</a>
</li>
<li>
<a href="#">
Accept payments
<p>Pre-build payments page</p>
</a>
</li>
<li>
<a href="#">
Close captioning
<p>Use AI to generate captions</p>
</a>
</li>
</ul>
<ul>
<li>
<a href="#">
Plugins
<p>Tweak existing functionality</p>
</a>
</li>
<li>
<a href="#">
Batch uploads
<p>Get your time back</p>
</a>
</li>
<li>
<a href="#">
Social sharing
<p>Generate content for socials</p>
</a>
</li>
</ul>
</div>
</li>
<li>
<button>Solutions</button>
<div>
<ul>
<li>
<a href="#">Creators</a>
</li>
<li>
<a href="#">Streamers</a>
</li>
<li>
<a href="#">Influence</a>
</li>
<li>
<a href="#">Programming</a>
</li>
<li>
<a href="#">Design</a>
</li>
</ul>
</div>
</li>
<li>
<button>Developers</button>
<div>
<a href="#">
Documentation
<p>Start integrating in no time</p>
</a>
<ul>
<li>
<a href="#">Libraries and SDKs</a>
</li>
<li>
<a href="#">Plugins</a>
</li>
<li>
<a href="#">Code samples</a>
</li>
<li>
<a href="#">Tutorials</a>
</li>
</ul>
<ul>
<li>
<a href="#">Accept online payments</a>
</li>
<li>
<a href="#">Editing video like a pro</a>
</li>
<li>
<a href="#">Automation techniques</a>
</li>
<li>
<a href="#">Create stunning effects</a>
</li>
</ul>
</div>
</li>
<li>
<button>Resources</button>
<ul>
<li>
<a href="#">Get Support</a>
</li>
<li>
<a href="#">Blog</a>
</li>
<li>
<a href="#">Case Studies</a>
</li>
<li>
<a href="#">Guides</a>
</li>
<li>
<a href="#">News & Events</a>
</li>
</ul>
</li>
<li>
<a href="#">Pricing</a>
</li>
</ul>
</nav>
<nav>
<ul>
<li>
<a href="#">Sign in</a>
</li>
</ul>
</nav>
</header>
Tailwind can transform this basic HTML markup into something extraordinary. Below is the final version. For a step-by-step guide, watch the accompanying video on this blog post.
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tailwind CSS Mega Nav</title>
</head>
<body
class="bg-gradient-to-br from-indigo-500 to-pink-700 via-blue-800 antialiased bg-no-repeat text-white"
>
<header
class="container mx-auto px-4 py-6 flex items-center justify-between"
>
<a href="#" class="font-bold text-white text-xl">Pipe</a>
<nav>
<ul class="flex items-center justify-center font-semibold">
<li class="relative group px-3 py-2">
<button
class="hover:opacity-50 cursor-default "
aria-haspopup="true"
>
Products
</button>
<div
class="absolute lg:-left-48 top-3 transition group-hover:translate-y-5 translate-y-0 opacity-0 invisible group-hover:opacity-100 group-hover:visible duration-500 ease-in-out group-hover:transform z-50 min-w-[560px] transform"
>
<div
class="relative top-6 p-6 bg-white rounded-xl shadow-xl w-full"
>
<div
class="w-10 h-10 bg-white transform rotate-45 absolute top-0 z-0 translate-x-0 transition-transform group-hover:translate-x-[12rem] duration-500 ease-in-out rounded-sm"
></div>
<div class="relative z-10">
<div class="grid grid-cols-2 gap-6">
<div>
<p
class="uppercase tracking-wider text-gray-500 font-medium text-[13px]"
>
The Suite
</p>
<ul class="mt-3 text-[15px]">
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Course Editor
<p class="text-gray-500 font-normal">
All in one editor
</p>
</a>
</li>
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Accept payments
<p class="text-gray-500 font-normal">
Pre-build payments page
</p>
</a>
</li>
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Close captioning
<p class="text-gray-500 font-normal">
Use AI to generate captions
</p>
</a>
</li>
</ul>
</div>
<div>
<p
class="uppercase tracking-wider text-gray-500 font-medium text-[13px]"
>
Extensions
</p>
<ul class="mt-4 text-[15px]">
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Plugins
<p class="text-gray-500 font-normal">
Tweak existing functionality
</p>
</a>
</li>
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Batch uploads
<p class="text-gray-500 font-normal">
Get your time back
</p>
</a>
</li>
<li>
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Social sharing
<p class="text-gray-500 font-normal">
Generate content for socials
</p>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</li>
<li class="relative group px-3 py-2">
<button
class="hover:opacity-50 cursor-default"
aria-haspopup="true"
>
Solutions
</button>
<div
class="absolute lg:-left-2 top-3 transition group-hover:translate-y-5 translate-y-0 opacity-0 invisible group-hover:opacity-100 group-hover:visible duration-500 ease-in-out group-hover:transform z-50 min-w-[260px] transform"
>
<div
class="relative top-6 p-6 bg-white rounded-xl shadow-xl w-full"
>
<div
class="w-10 h-10 bg-white transform rotate-45 absolute top-0 z-0 -translate-x-4 transition-transform group-hover:translate-x-3 duration-500 ease-in-out rounded-sm"
></div>
<div class="relative z-10">
<p
class="uppercase tracking-wider text-gray-500 font-medium text-[13px]"
>
Use cases
</p>
<ul class="mt-3 text-[15px]">
<li>
<a
href="#"
class="bg-transparent bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-pink-700 via-blue-500 font-semibold hover:from-blue-600 hover:to-indigo-600 hover:via-pink-400 py-1 block"
>
Creators
</a>
</li>
<li>
<a
href="#"
class="bg-transparent bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-pink-700 via-blue-500 font-semibold hover:from-blue-600 hover:to-indigo-600 hover:via-pink-400 py-1 block"
>
Streamers
</a>
</li>
<li>
<a
href="#"
class="bg-transparent bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-pink-700 via-blue-500 font-semibold hover:from-blue-600 hover:to-indigo-600 hover:via-pink-400 py-1 block"
>
Influence
</a>
</li>
<li>
<a
href="#"
class="bg-transparent bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-pink-700 via-blue-500 font-semibold hover:from-blue-600 hover:to-indigo-600 hover:via-pink-400 py-2"
>
Programming
</a>
</li>
<li>
<a
href="#"
class="bg-transparent bg-clip-text text-transparent bg-gradient-to-br from-indigo-400 to-pink-700 via-blue-500 font-semibold hover:from-blue-600 hover:to-indigo-600 hover:via-pink-400 py-1 block"
>
Design
</a>
</li>
</ul>
</div>
</div>
</div>
</li>
<li class="px-3 py-2 relative group">
<button
class="hover:opacity-50 cursor-default"
aria-haspopup="true"
>
Developers
</button>
<div
class="absolute lg:-left-24 top-3 transition group-hover:translate-y-5 translate-y-0 opacity-0 invisible group-hover:opacity-100 group-hover:visible duration-500 ease-in-out group-hover:transform z-50 min-w-[560px] transform"
>
<div
class="relative top-6 p-6 bg-white rounded-xl shadow-xl w-full"
>
<div
class="w-10 h-10 bg-white transform rotate-45 absolute top-0 z-0 -translate-x-4 transition-transform group-hover:translate-x-[105px] duration-500 ease-in-out rounded-sm"
></div>
<div class="relative z-10">
<a
href="#"
class="block p-2 -mx-2 rounded-lg hover:bg-gradient-to-br hover:from-indigo-50 hover:to-pink-50 hover:via-blue-50 transition ease-in-out duration-300 text-gray-800 font-semibold hover:text-indigo-600"
>
Documentation
<p class="text-gray-500 font-normal">
Start integrating in no time
</p>
</a>
<div class="grid grid-cols-2 gap-6 mt-6">
<div>
<p
class="uppercase tracking-wider text-gray-500 text-[13px]"
>
Get started
</p>
<ul class="mt-3 text-[15px]">
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Libraries and SDKs
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Plugins
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Code samples
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Tutorials
</a>
</li>
</ul>
</div>
<div>
<p
class="uppercase tracking-wider text-gray-500 font-medium text-[13px]"
>
Guides
</p>
<ul class="mt-3 text-[15px]">
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Accept online payments
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Editing video like a pro
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Automation techniques
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Create stunning effects
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</li>
<li class="px-3 py-2 relative group">
<button
class="hover:opacity-50 cursor-default"
aria-haspopup="true"
>
Resources
</button>
<div
class="absolute lg:-left-2 top-3 transition group-hover:translate-y-5 translate-y-0 opacity-0 invisible group-hover:opacity-100 group-hover:visible duration-500 ease-in-out group-hover:transform z-50 min-w-[220px] transform"
>
<div
class="relative top-6 p-6 bg-white rounded-xl shadow-xl w-full"
>
<div
class="w-10 h-10 bg-white transform rotate-45 absolute top-0 z-0 -translate-x-4 transition-transform group-hover:translate-x-3 duration-500 ease-in-out rounded-sm"
></div>
<div class="relative z-10">
<ul class="text-[15px]">
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Get Support
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Blog
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Case Studies
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
Guides
</a>
</li>
<li>
<a
href="#"
class="text-gray-600 hover:text-gray-800 py-1 block font-normal"
>
News & Events
</a>
</li>
</ul>
</div>
</div>
</div>
</li>
<li class="px-3 py-2 relative group">
<a href="#" class="hover:opacity-50 cursor-default">Pricing</a>
</li>
</ul>
</nav>
<nav>
<ul>
<li>
<a
href="#"
class="rounded-full px-3 py-2 font-semibold bg-white bg-opacity-10 flex items-center group"
>
<span class="mr-2">Sign in</span>
<svg
class="stroke-current"
width="10"
height="10"
stroke-width="2"
viewBox="0 0 10 10"
aria-hidden="true"
>
<g fill-rule="evenodd">
<path
class="opacity-0 group-hover:opacity-100 transition ease-in-out duration-200"
d="M0 5h7"
></path>
<path
class="opacity-100 group-hover:transform group-hover:translate-x-1 transition ease-in-out duration-00"
d="M1 1l4 4-4 4"
></path>
</g>
</svg>
</a>
</li>
</ul>
</nav>
</header>
<div
class="flex items-center justify-between absolute bottom-0 inset-x-0 pb-4 w-full container mx-auto px-4"
>
<a
href="https://web-crunch.com"
class="flex items-center group"
target="_blank"
>
<img src="/web-crunch.svg" alt="Web Crunch logo" class="w-8 h-8 mr-2" />
<p class="text-neutral-200 group-hover:underline ">
Read or watch the full tutorial at web-crunch.com
</p>
</a>
<div class="flex items-center space-x-4">
<a href="https://youtube.com/c/webcrunch" target="_blank" class="group">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="fill-current text-neutral-200 group-hover:text-neutral-300"
>
<title>youtube</title>
<path
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
></path>
</svg>
</a>
<a href="https://github.com/justalever" target="_blank" class="group">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="fill-current text-neutral-200 group-hover:text-neutral-300"
>
<title>github</title>
<path
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
></path>
</svg>
</a>
</div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>
Categories
Collection
Part of the Tailwind CSS collection
Products and courses
-
Hello Hotwire
A course on Hotwire + Ruby on Rails.
-
Hello Rails
A course for newcomers to Ruby on Rails.
-
Rails UI
UI templates and components for Rails.