A responsive navbar needs readable links, a clear mobile disclosure, and predictable keyboard behavior. Start with ordinary navigation links and a button that reports whether its controlled panel is open. Choose the visual pattern afterward: classic, sticky, transparent, centered, or sidebar.
1. A complete mobile disclosure
Example setup: Tailwind CSS 4.1.18, compiled locally, with plain HTML and vanilla JavaScript. These small educational examples are separate from the membership library. Adapt them to your application and test your final content and browser requirements.
Complete HTML, CSS, and JavaScript
Use your compiled Tailwind stylesheet in place of /examples/tailwind.css. The example uses Tailwind CSS 4 utilities and vanilla JavaScript.
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,follow"><title>A responsive navigation disclosure</title><link rel="stylesheet" href="/examples/tailwind.css"><style>body{font-family:system-ui,sans-serif;background:#faf9f6;color:#252824;padding:24px}button{cursor:pointer}button:disabled{cursor:wait;opacity:.6}:focus-visible{outline:3px solid #4f46e5;outline-offset:4px}#links:not([hidden]){display:flex} [hidden]{display:none!important} main section{display:inline-block;margin:16px 16px 0 0;scroll-margin-top:16px}</style></head><body><nav aria-label="Example navigation" class="rounded-2xl border border-stone-200 bg-white p-4">
<div class="flex items-center justify-between gap-4">
<a href="#content" class="font-bold">Fieldwork</a>
<button id="toggle" aria-controls="links" aria-expanded="false" class="rounded-lg border px-4 py-2 md:hidden">Menu</button>
<div class="hidden gap-6 md:flex"><a href="#work">Work</a><a href="#about">About</a><a href="#contact">Contact</a></div>
</div>
<div id="links" hidden class="mt-4 flex-col gap-3 border-t pt-4 md:hidden"><a href="#work">Work</a><a href="#about">About</a><a href="#contact">Contact</a></div>
</nav>
<main id="content" class="py-6"><h1 class="text-2xl font-semibold">Room for your next idea.</h1><p class="mt-2 text-stone-600">Resize this example below 768px to try the menu.</p><section id="work" tabindex="-1">Work</section><section id="about" tabindex="-1">About</section><section id="contact" tabindex="-1">Contact</section></main><script>const toggle = document.querySelector('#toggle');
const links = document.querySelector('#links');
function closeMenu(restoreFocus = false) {
links.hidden = true;
toggle.setAttribute('aria-expanded', 'false');
if (restoreFocus) toggle.focus();
}
toggle.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') !== 'true';
toggle.setAttribute('aria-expanded', String(open));
links.hidden = !open;
});
document.addEventListener('keydown', event => { if (event.key === 'Escape' && !links.hidden) closeMenu(true); });
document.addEventListener('click', event => { if (!event.target.closest('nav')) closeMenu(); });
links.addEventListener('click', event => { if (event.target.closest('a')) closeMenu(); });
matchMedia('(min-width: 768px)').addEventListener('change', () => closeMenu());</script></body></html>The desktop links become visible at the medium breakpoint. Below that width, the Menu button toggles a separate set of links using the native hidden attribute. Escape closes the panel and restores focus; clicking elsewhere closes it without moving focus. Crossing the desktop breakpoint resets the mobile state.
This is site navigation, not an application menu. Keep ordinary links and their normal Tab behavior. The WAI-ARIA disclosure navigation example explains why menu roles are usually unnecessary for this pattern.
2. A sticky header
Use the same behavior and change the outer positioning. Keep the header’s stacking level consistent with dialogs and other overlays. If it covers in-page targets, give those targets a suitable scroll margin.
<header class="sticky top-0 z-40 border-b bg-white/95 backdrop-blur-sm">
<!-- Place the navigation inside this header. -->
</header>
<section id="features" class="scroll-mt-24">…</section>
3. A transparent header over a hero
Place the header inside a relatively positioned hero. Add a reliable contrast layer behind links instead of assuming every image is dark. Give the opened mobile panel an opaque background. If the hero uses overflow clipping, check whether an expanded menu remains inside it.
<section class="relative">
<header class="absolute inset-x-0 top-0 z-20 bg-black/60 text-white">…</header>
<div class="pt-28">Your hero content</div>
</section>
4. A centered logo with balanced links
Use a three-column desktop grid and preserve a sensible source order. Avoid moving links into a visual order that disagrees with keyboard navigation. On mobile, return to a logo and disclosure button rather than compressing both link groups around the logo.
<div class="hidden grid-cols-[1fr_auto_1fr] items-center gap-8 md:grid">
<div class="flex gap-4">Primary links</div>
<a href="/" aria-label="Your brand home">Brand</a>
<div class="flex justify-end gap-4">Account links</div>
</div>
5. Sidebar navigation
A persistent desktop sidebar can use the same disclosure idea for narrow screens. Keep the opened panel in the page flow if it does not need to behave like a modal. If you make it an overlay drawer that blocks the page, use a dialog implementation with focus containment, an accessible label, Escape handling, and focus restoration.
<div class="md:grid md:grid-cols-[16rem_1fr]">
<aside aria-label="Section navigation">Your navigation</aside>
<main class="min-w-0">Your page content</main>
</div>
Before using the navbar in your project
- Test long navigation labels at 320px and at browser zoom.
- Confirm hidden links cannot receive focus.
- Open the menu, resize to desktop, then return to mobile.
- Verify every link has a real destination.
- Test the final theme’s contrast and focus indicator.
If a panel is clipped or leaves the screen, use the dropdown troubleshooting guide. For a finished visual starting point, explore the capsule navbar and header layouts.
