10 / 20
All 20 in 20 Tailwind CSS Responsive Navbars
- 01Tailwind Glassmorphism Frosted Navbar
- 02Tailwind Mega Menu Dropdown Navbar
- 03Tailwind Sidebar Drawer Navigation
- 04Tailwind Animated Underline Tabs Navbar
- 05Tailwind Pill Highlight Navigation Bar
- 06Tailwind Scroll-Aware Shrink Navbar
- 07Tailwind Neon Dark Navbar
- 08Tailwind Breadcrumb Reading Progress Navbar
- 09Tailwind Split Two-Tone Navbar
- 10Tailwind Bottom Tab Bar Navigation
- 11Tailwind Gradient Border Animated Navbar
- 12Tailwind Centered Logo Navbar
- 13Tailwind Icon Dot Indicator Navbar
- 14Tailwind Full-Screen Overlay Menu
- 15Tailwind Morphing Search Expand Navbar
- 16Tailwind Floating Island Multi-Segment Navbar
- 17Tailwind Step Progress Wizard Navbar
- 18Tailwind Vertical Rail Sidebar Navbar
- 19Tailwind Announcement Bar Dual Navbar
- 20Tailwind Scroll Spy Active Highlight Navbar
Tailwind Bottom Tab Bar Navigation
Desktop gets a conventional top bar; phones get an iOS-style bottom tab bar with a lifted centre action. The pair is one component: hidden md:flex on the top nav, md:hidden on the tab bar, and pb-[env(safe-area-inset-bottom)] so the home indicator never covers a tab.
Complete Tailwind CSS landing page templates in HTML, React, Next.js and Vue · from $49
Cruip · Affiliate link
The code
<div class="tnb-10 w-full min-h-svh bg-tnb10-page font-tnb10-sans text-tnb10-ink" aria-label="Bottom tab bar navigation demo">
<nav class="hidden h-16 items-center gap-6 border-b border-tnb10-edge bg-white px-8 shadow-[0_1px_3px_oklch(0_0_0/0.05)] md:flex" aria-label="Primary">
<a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.02em] text-tnb10-ink no-underline">Pulse<span class="text-tnb10-acc">.</span></a>
<ul class="flex flex-1 list-none items-center gap-0">
<li><a href="#home" aria-current="page" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-acc no-underline aria-[current=page]:bg-tnb10-tint"><span aria-hidden="true">🏠</span>Home</a></li>
<li><a href="#analytics" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📊</span>Analytics</a></li>
<li><a href="#messages" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">💬</span>Messages</a></li>
<li><a href="#files" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📁</span>Files</a></li>
<li><a href="#profile" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">👤</span>Profile</a></li>
</ul>
<a href="#upgrade" class="ml-auto shrink-0 rounded-lg bg-tnb10-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb10-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Upgrade plan</a>
</nav>
<nav class="fixed inset-x-0 bottom-0 z-200 border-t border-tnb10-edge bg-white pb-[env(safe-area-inset-bottom)] shadow-[0_-4px_20px_oklch(0_0_0/0.07)] md:hidden" aria-label="Primary">
<ul class="flex list-none items-stretch px-2">
<li class="flex-1"><a href="#home" aria-current="page" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 aria-[current=page]:text-tnb10-acc"><span class="grid h-7 w-9 place-items-center rounded-full text-xl transition-[background,transform] duration-200 group-hover:bg-tnb10-hover aria-[current=page]:bg-tnb10-tint" aria-hidden="true">🏠</span>Home</a></li>
<li class="flex-1"><a href="#stats" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">📊</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">2</span>Stats</a></li>
<li class="flex-1"><a href="#new" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-acc no-underline"><span class="grid h-10 w-11 -translate-y-2 place-items-center rounded-2xl bg-linear-[135deg,var(--color-tnb10-acc),var(--color-tnb10-acc2)] text-2xl text-white shadow-[0_4px_12px_oklch(0.59_0.2_278/0.45)] transition-transform duration-200 hover:-translate-y-2.5 hover:scale-105 motion-reduce:transition-none" aria-hidden="true">+</span>New</a></li>
<li class="flex-1"><a href="#chat" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">💬</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">5</span>Chat</a></li>
<li class="flex-1"><a href="#profile" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">👤</span>Profile</a></li>
</ul>
</nav>
<main class="mx-auto max-w-3xl px-5 pt-10 pb-28 md:px-8 md:pb-16">
<h1 class="mb-4 text-3xl font-extrabold tracking-[-0.03em] text-tnb10-ink md:text-4xl">Bottom Tab Bar Navigation</h1>
<p class="text-lg leading-relaxed text-tnb10-mut">Narrow the frame: the top bar leaves and the thumb bar arrives, centre action lifted out of the strip. The bottom inset is <code class="rounded bg-tnb10-tint px-1.5 py-0.5 text-[0.9em] text-tnb10-acc">pb-[env(safe-area-inset-bottom)]</code>, which is zero on hardware that has no notch.</p>
<div class="mt-8 grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Five tabs maximum — beyond that, labels truncate and the bar stops being scannable.</div>
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Badges use <code>ring-2 ring-white</code>, so retinting the bar does not orphan a white border.</div>
</div>
</main>
</div><div class="tnb-10 w-full min-h-svh bg-tnb10-page font-tnb10-sans text-tnb10-ink" aria-label="Bottom tab bar navigation demo">
<nav class="hidden h-16 items-center gap-6 border-b border-tnb10-edge bg-white px-8 shadow-[0_1px_3px_oklch(0_0_0/0.05)] md:flex" aria-label="Primary">
<a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.02em] text-tnb10-ink no-underline">Pulse<span class="text-tnb10-acc">.</span></a>
<ul class="flex flex-1 list-none items-center gap-0">
<li><a href="#home" aria-current="page" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-acc no-underline aria-[current=page]:bg-tnb10-tint"><span aria-hidden="true">🏠</span>Home</a></li>
<li><a href="#analytics" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📊</span>Analytics</a></li>
<li><a href="#messages" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">💬</span>Messages</a></li>
<li><a href="#files" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📁</span>Files</a></li>
<li><a href="#profile" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">👤</span>Profile</a></li>
</ul>
<a href="#upgrade" class="ml-auto shrink-0 rounded-lg bg-tnb10-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb10-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Upgrade plan</a>
</nav>
<nav class="fixed inset-x-0 bottom-0 z-200 border-t border-tnb10-edge bg-white pb-[env(safe-area-inset-bottom)] shadow-[0_-4px_20px_oklch(0_0_0/0.07)] md:hidden" aria-label="Primary">
<ul class="flex list-none items-stretch px-2">
<li class="flex-1"><a href="#home" aria-current="page" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 aria-[current=page]:text-tnb10-acc"><span class="grid h-7 w-9 place-items-center rounded-full text-xl transition-[background,transform] duration-200 group-hover:bg-tnb10-hover aria-[current=page]:bg-tnb10-tint" aria-hidden="true">🏠</span>Home</a></li>
<li class="flex-1"><a href="#stats" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">📊</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">2</span>Stats</a></li>
<li class="flex-1"><a href="#new" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-acc no-underline"><span class="grid h-10 w-11 -translate-y-2 place-items-center rounded-2xl bg-linear-[135deg,var(--color-tnb10-acc),var(--color-tnb10-acc2)] text-2xl text-white shadow-[0_4px_12px_oklch(0.59_0.2_278/0.45)] transition-transform duration-200 hover:-translate-y-2.5 hover:scale-105 motion-reduce:transition-none" aria-hidden="true">+</span>New</a></li>
<li class="flex-1"><a href="#chat" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">💬</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">5</span>Chat</a></li>
<li class="flex-1"><a href="#profile" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">👤</span>Profile</a></li>
</ul>
</nav>
<main class="mx-auto max-w-3xl px-5 pt-10 pb-28 md:px-8 md:pb-16">
<h1 class="mb-4 text-3xl font-extrabold tracking-[-0.03em] text-tnb10-ink md:text-4xl">Bottom Tab Bar Navigation</h1>
<p class="text-lg leading-relaxed text-tnb10-mut">Narrow the frame: the top bar leaves and the thumb bar arrives, centre action lifted out of the strip. The bottom inset is <code class="rounded bg-tnb10-tint px-1.5 py-0.5 text-[0.9em] text-tnb10-acc">pb-[env(safe-area-inset-bottom)]</code>, which is zero on hardware that has no notch.</p>
<div class="mt-8 grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Five tabs maximum — beyond that, labels truncate and the bar stops being scannable.</div>
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Badges use <code>ring-2 ring-white</code>, so retinting the bar does not orphan a white border.</div>
</div>
</main>
</div>@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The
env(safe-area-inset-bottom)padding, a footnote in the CSS original's gotchas, is now a visible utility on the bar — the kind of detail that survives a refactor only when it is written where the bar is. - Active state is
aria-[current=page]:on the tab, the icon pill and the label at once, so one attribute change moves the whole treatment. - Badge cutouts moved from
border: 2px solid var(--bg)toring-2 ring-white, which composites instead of eating 4px of the badge's box. - The two surfaces stay as two navs on purpose: a hover row and a thumb bar are different controls, and pretending they are one produces the worst of both.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Bottom Tab Bar Navigation
Source: https://codefronts.com/navigation/tailwind-css-responsive-navbars/tailwind-bottom-tab-bar-navigation/
Desktop gets a conventional top bar; phones get an iOS-style bottom tab bar with a lifted centre action. The pair is one component: hidden md:flex on the top nav, md:hidden on the tab bar, and pb-[env(safe-area-inset-bottom)] so the home indicator never covers a tab.
## HTML
```html
<div class="tnb-10 w-full min-h-svh bg-tnb10-page font-tnb10-sans text-tnb10-ink" aria-label="Bottom tab bar navigation demo">
<nav class="hidden h-16 items-center gap-6 border-b border-tnb10-edge bg-white px-8 shadow-[0_1px_3px_oklch(0_0_0/0.05)] md:flex" aria-label="Primary">
<a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.02em] text-tnb10-ink no-underline">Pulse<span class="text-tnb10-acc">.</span></a>
<ul class="flex flex-1 list-none items-center gap-0">
<li><a href="#home" aria-current="page" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-acc no-underline aria-[current=page]:bg-tnb10-tint"><span aria-hidden="true">🏠</span>Home</a></li>
<li><a href="#analytics" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📊</span>Analytics</a></li>
<li><a href="#messages" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">💬</span>Messages</a></li>
<li><a href="#files" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📁</span>Files</a></li>
<li><a href="#profile" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">👤</span>Profile</a></li>
</ul>
<a href="#upgrade" class="ml-auto shrink-0 rounded-lg bg-tnb10-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb10-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Upgrade plan</a>
</nav>
<nav class="fixed inset-x-0 bottom-0 z-200 border-t border-tnb10-edge bg-white pb-[env(safe-area-inset-bottom)] shadow-[0_-4px_20px_oklch(0_0_0/0.07)] md:hidden" aria-label="Primary">
<ul class="flex list-none items-stretch px-2">
<li class="flex-1"><a href="#home" aria-current="page" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 aria-[current=page]:text-tnb10-acc"><span class="grid h-7 w-9 place-items-center rounded-full text-xl transition-[background,transform] duration-200 group-hover:bg-tnb10-hover aria-[current=page]:bg-tnb10-tint" aria-hidden="true">🏠</span>Home</a></li>
<li class="flex-1"><a href="#stats" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">📊</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">2</span>Stats</a></li>
<li class="flex-1"><a href="#new" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-acc no-underline"><span class="grid h-10 w-11 -translate-y-2 place-items-center rounded-2xl bg-linear-[135deg,var(--color-tnb10-acc),var(--color-tnb10-acc2)] text-2xl text-white shadow-[0_4px_12px_oklch(0.59_0.2_278/0.45)] transition-transform duration-200 hover:-translate-y-2.5 hover:scale-105 motion-reduce:transition-none" aria-hidden="true">+</span>New</a></li>
<li class="flex-1"><a href="#chat" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">💬</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">5</span>Chat</a></li>
<li class="flex-1"><a href="#profile" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">👤</span>Profile</a></li>
</ul>
</nav>
<main class="mx-auto max-w-3xl px-5 pt-10 pb-28 md:px-8 md:pb-16">
<h1 class="mb-4 text-3xl font-extrabold tracking-[-0.03em] text-tnb10-ink md:text-4xl">Bottom Tab Bar Navigation</h1>
<p class="text-lg leading-relaxed text-tnb10-mut">Narrow the frame: the top bar leaves and the thumb bar arrives, centre action lifted out of the strip. The bottom inset is <code class="rounded bg-tnb10-tint px-1.5 py-0.5 text-[0.9em] text-tnb10-acc">pb-[env(safe-area-inset-bottom)]</code>, which is zero on hardware that has no notch.</p>
<div class="mt-8 grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Five tabs maximum — beyond that, labels truncate and the bar stops being scannable.</div>
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Badges use <code>ring-2 ring-white</code>, so retinting the bar does not orphan a white border.</div>
</div>
</main>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Bottom Tab Bar Navigation
Source: https://codefronts.com/navigation/tailwind-css-responsive-navbars/tailwind-bottom-tab-bar-navigation/
Desktop gets a conventional top bar; phones get an iOS-style bottom tab bar with a lifted centre action. The pair is one component: hidden md:flex on the top nav, md:hidden on the tab bar, and pb-[env(safe-area-inset-bottom)] so the home indicator never covers a tab.
## HTML
```html
<div class="tnb-10 w-full min-h-svh bg-tnb10-page font-tnb10-sans text-tnb10-ink" aria-label="Bottom tab bar navigation demo">
<nav class="hidden h-16 items-center gap-6 border-b border-tnb10-edge bg-white px-8 shadow-[0_1px_3px_oklch(0_0_0/0.05)] md:flex" aria-label="Primary">
<a href="#home" class="shrink-0 text-xl font-extrabold tracking-[-0.02em] text-tnb10-ink no-underline">Pulse<span class="text-tnb10-acc">.</span></a>
<ul class="flex flex-1 list-none items-center gap-0">
<li><a href="#home" aria-current="page" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-acc no-underline aria-[current=page]:bg-tnb10-tint"><span aria-hidden="true">🏠</span>Home</a></li>
<li><a href="#analytics" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📊</span>Analytics</a></li>
<li><a href="#messages" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">💬</span>Messages</a></li>
<li><a href="#files" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">📁</span>Files</a></li>
<li><a href="#profile" class="flex items-center gap-1.5 rounded-lg px-3.5 py-2 text-sm font-bold text-tnb10-mut no-underline transition-colors duration-150 hover:bg-tnb10-tint hover:text-tnb10-acc"><span aria-hidden="true">👤</span>Profile</a></li>
</ul>
<a href="#upgrade" class="ml-auto shrink-0 rounded-lg bg-tnb10-acc px-4 py-2 text-sm font-bold text-white no-underline transition-[background,translate] duration-200 hover:-translate-y-px hover:bg-tnb10-accdark motion-reduce:transition-none motion-reduce:hover:translate-y-0">Upgrade plan</a>
</nav>
<nav class="fixed inset-x-0 bottom-0 z-200 border-t border-tnb10-edge bg-white pb-[env(safe-area-inset-bottom)] shadow-[0_-4px_20px_oklch(0_0_0/0.07)] md:hidden" aria-label="Primary">
<ul class="flex list-none items-stretch px-2">
<li class="flex-1"><a href="#home" aria-current="page" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 aria-[current=page]:text-tnb10-acc"><span class="grid h-7 w-9 place-items-center rounded-full text-xl transition-[background,transform] duration-200 group-hover:bg-tnb10-hover aria-[current=page]:bg-tnb10-tint" aria-hidden="true">🏠</span>Home</a></li>
<li class="flex-1"><a href="#stats" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">📊</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">2</span>Stats</a></li>
<li class="flex-1"><a href="#new" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-acc no-underline"><span class="grid h-10 w-11 -translate-y-2 place-items-center rounded-2xl bg-linear-[135deg,var(--color-tnb10-acc),var(--color-tnb10-acc2)] text-2xl text-white shadow-[0_4px_12px_oklch(0.59_0.2_278/0.45)] transition-transform duration-200 hover:-translate-y-2.5 hover:scale-105 motion-reduce:transition-none" aria-hidden="true">+</span>New</a></li>
<li class="flex-1"><a href="#chat" class="relative flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">💬</span><span class="absolute top-1.5 right-[calc(50%-22px)] min-w-4 rounded-full bg-tnb10-danger px-1.5 text-center text-[10px] leading-4 font-extrabold text-white ring-2 ring-white">5</span>Chat</a></li>
<li class="flex-1"><a href="#profile" class="flex min-h-14 flex-col items-center justify-center gap-0.5 rounded-lg text-[11px] font-bold text-tnb10-mut no-underline transition-colors duration-200 hover:text-tnb10-ink"><span class="grid h-7 w-9 place-items-center rounded-full text-xl" aria-hidden="true">👤</span>Profile</a></li>
</ul>
</nav>
<main class="mx-auto max-w-3xl px-5 pt-10 pb-28 md:px-8 md:pb-16">
<h1 class="mb-4 text-3xl font-extrabold tracking-[-0.03em] text-tnb10-ink md:text-4xl">Bottom Tab Bar Navigation</h1>
<p class="text-lg leading-relaxed text-tnb10-mut">Narrow the frame: the top bar leaves and the thumb bar arrives, centre action lifted out of the strip. The bottom inset is <code class="rounded bg-tnb10-tint px-1.5 py-0.5 text-[0.9em] text-tnb10-acc">pb-[env(safe-area-inset-bottom)]</code>, which is zero on hardware that has no notch.</p>
<div class="mt-8 grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Five tabs maximum — beyond that, labels truncate and the bar stops being scannable.</div>
<div class="rounded-2xl border border-tnb10-edge bg-white p-5 text-sm text-tnb10-mut">Badges use <code>ring-2 ring-white</code>, so retinting the bar does not orphan a white border.</div>
</div>
</main>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tnb10-page: #f7f7fb;
--color-tnb10-page: oklch(0.98 0.004 280);
--color-tnb10-ink: #1e1b4b;
--color-tnb10-ink: oklch(0.28 0.08 280);
--color-tnb10-mut: #8a8fa3;
--color-tnb10-mut: oklch(0.65 0.02 275);
--color-tnb10-edge: #e5e7eb;
--color-tnb10-edge: oklch(0.91 0.005 265);
--color-tnb10-hover: #f3f4f6;
--color-tnb10-hover: oklch(0.96 0.003 265);
--color-tnb10-tint: #eef2ff;
--color-tnb10-tint: oklch(0.95 0.02 275);
--color-tnb10-acc: #6366f1;
--color-tnb10-acc: oklch(0.59 0.2 278);
--color-tnb10-acc2: #8b5cf6;
--color-tnb10-acc2: oklch(0.63 0.22 295);
--color-tnb10-accdark: #4f46e5;
--color-tnb10-accdark: oklch(0.53 0.22 278);
--color-tnb10-danger: #ef4444;
--color-tnb10-danger: oklch(0.63 0.22 25);
--font-tnb10-sans: 'Nunito', system-ui, sans-serif;
}
.tnb-10 {
width: 100%;
min-height: 100svh;
}
.tnb-10 ::selection {
background: var(--color-tnb10-acc);
color: #fff;
}
```How this works
Two navs, one contract. Nothing is duplicated: the links are written once per surface because the surfaces are genuinely different controls — a hover-driven row and a thumb-driven bar. The breakpoint decides which exists:
<nav class="hidden md:flex"> … top bar … </nav>
<nav class="fixed bottom-0 md:hidden"> … tab bar … </nav>The safe area is not optional. On a notched iPhone the bottom 34px belong to the system; pb-[env(safe-area-inset-bottom)] gives them back, and evaluates to zero everywhere else.
The content column reserves room with pb-24 md:pb-16, so the last paragraph is never trapped under the bar.
Make it yours
- Five tabs is the ceiling; past that drop the labels and keep icons with
aria-labels. - Flat centre tab: remove the
-translate-y-2and the gradient to get a fifth ordinary tab. - Blur the bar over content: add
bg-white/85 backdrop-blur-lg. - Swap emoji for SVG: the icon slot is a fixed
size-*box, so an inline SVG drops straight in.
Gotchas — read before shipping
- Without
env(safe-area-inset-bottom)the last row of tabs sits under the iOS home indicator and mis-taps constantly. - A fixed bottom bar overlaps content unless the page reserves bottom padding — this demo does it on the main column.
- The lifted centre tab escapes the bar's box; do not add
overflow-hiddento the bar. - Badges need a ring in the bar's own background colour, not a white border, or they look wrong the moment you tint the bar.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
env(safe-area-inset-*) needs Safari 11.1+ and a viewport meta with viewport-fit=cover on iOS.