Crafting a mobile menu with Tailwind CSS without JavaScript
Tags: webdev, css, html, javascript
Published: 2023-04-28 08:34:10

Welcome to this blog post, where I'll walk you through building a mobile menu using only [Tailwind CSS](https://tailwindcss.com/) and HTML, without JavaScript. This approach is excellent for enhancing website performance, as minimizing the use of JavaScript can help your site load faster. You can check out a [live example](https://straffesites.com/en) of this technique on my website. Let's get started!

## Using `peer-*` from Tailwind CSS for animations and state
To create the animations for our mobile menu, we'll utilize the [`peer-*` utility from Tailwind CSS](https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state). This allows us to control the state of a sibling element, like an `<input>` element of the type `checkbox`. By placing all HTML elements within the `<label>` element, we can make them dependent on the state of the `<input>` element. We will then hide the `<input>` element and make the `<label>` element respond to touch or cursor.


```html
<label class="relative z-40 cursor-pointer px-3 py-6" for="mobile-menu">
   <input class="peer hidden" type="checkbox" id="mobile-menu" />
</label>
```

## Creating the hamburger icon with `before:` and `after:` pseudo-elements
To craft the hamburger icon, we'll use the [`before:` and `after:` pseudo-elements](https://tailwindcss.com/docs/hover-focus-and-other-states#before-and-after). We'll start with a `<div>` element with a height of `1px` and a width equal to the `w-7` value. In this example, the middle line is set to `transparent`, so we only see the lines from `before:` and `after:`


```html
<label class="relative z-40 cursor-pointer px-3 py-6" for="mobile-menu">
	<input class="peer hidden" type="checkbox" id="mobile-menu" />
	<div
    	class="relative z-50 block h-[1px] w-7 bg-black bg-transparent content-[''] before:absolute before:top-[-0.35rem] before:z-50 before:block before:h-full before:w-full before:bg-black before:transition-all before:duration-200 before:ease-out before:content-[''] after:absolute after:right-0 after:bottom-[-0.35rem] after:block after:h-full after:w-full after:bg-black after:transition-all after:duration-200 after:ease-out after:content-[''] peer-checked:bg-transparent before:peer-checked:top-0 before:peer-checked:w-full before:peer-checked:rotate-45 before:peer-checked:transform after:peer-checked:bottom-0 after:peer-checked:w-full after:peer-checked:-rotate-45 after:peer-checked:transform"
	>
	</div>
</label>
```

## Completing the mobile menu with additional elements
Now, let's add more elements to complete the mobile menu:
- A full-screen background with a [backdrop blur](https://tailwindcss.com/docs/backdrop-blur) filter
- A `<div>` element for the menu items with an [animation](https://tailwindcss.com/docs/animation), which scrolls the menu from right to left
- The menu itself, using a `<menu>` element (which functions like a `<ul>` element, but is better for [semantics in HTML](https://dev.to/seppegadeyne/unlocking-the-power-of-semantics-in-html-4e9j))

```html
<label class="relative z-40 cursor-pointer px-3 py-6" for="mobile-menu">
	<input class="peer hidden" type="checkbox" id="mobile-menu" />
	<div
		class="relative z-50 block h-[1px] w-7 bg-black bg-transparent content-[''] before:absolute before:top-[-0.35rem] before:z-50 before:block before:h-full before:w-full before:bg-black before:transition-all before:duration-200 before:ease-out before:content-[''] after:absolute after:right-0 after:bottom-[-0.35rem] after:block after:h-full after:w-full after:bg-black after:transition-all after:duration-200 after:ease-out after:content-[''] peer-checked:bg-transparent before:peer-checked:top-0 before:peer-checked:w-full before:peer-checked:rotate-45 before:peer-checked:transform after:peer-checked:bottom-0 after:peer-checked:w-full after:peer-checked:-rotate-45 after:peer-checked:transform"
	>
	</div>
	<div
		class="fixed inset-0 z-40 hidden h-full w-full bg-black/50 backdrop-blur-sm peer-checked:block"
	>
		&nbsp;
	</div>
	<div
		class="fixed top-0 right-0 z-40 h-full w-full translate-x-full overflow-y-auto overscroll-y-none transition duration-500 peer-checked:translate-x-0"
	>
		<div class="float-right min-h-full w-[85%] bg-white px-6 pt-12 shadow-2xl">
			<menu>
				<li><a href="/">Home</a></li>
				<li><a href="/contact">Contact</a></li>
			</menu>
		</div>
	</div>
</label>
```

## Conclusion
In this blog post, we've successfully built a lightweight mobile menu using [Tailwind CSS](https://tailwindcss.com) and HTML without JavaScript. This approach is crucial for optimizing your website's load speed and [ranking higher in search engines](https://straffesites.com/en/blog/how-to-rank-higher-on-google). So try and experience the benefits of a more performant, JavaScript-free mobile menu.