11 / 15
All 15 in 15 Tailwind CSS Navigation Menus
- 01Tailwind CSS Navbar with Animated Hover Underline
- 02Tailwind CSS Dropdown Menu — Hover & Keyboard Accessible
- 03Tailwind CSS Mega Menu Navigation
- 04Tailwind CSS Hamburger Menu with Slide-Out Drawer
- 05Tailwind CSS Full-Screen Overlay Menu
- 06Tailwind CSS Sticky Navbar That Shrinks on Scroll
- 07Tailwind CSS Collapsible Sidebar Navigation
- 08Tailwind CSS Tabs with Animated Sliding Indicator
- 09Tailwind CSS Breadcrumb Navigation Examples
- 10Glassmorphism Navbar in Tailwind CSS
- 11Tailwind CSS Mobile Bottom Navigation Bar with Animated Icons
- 12Tailwind CSS Multi-Level Accordion Sidebar Menu
- 13Tailwind CSS Navbar with Magnetic Hover Effect
- 14Tailwind CSS Neon Glow Navigation Menu
- 15Tailwind CSS Animated Pill Navigation Indicator
Tailwind CSS Mobile Bottom Navigation Bar with Animated Icons
An app-style floating dock: five icons, and the active one expands into a tinted pill that reveals its label, each tab in its own colour. Icons spring on selection, a Messages badge shows until you open Messages, and the page above swaps with a starting: fade. Radios behind the scenes mean arrow keys work. Zero JavaScript.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<div class="tnv-11 group/root flex min-h-svh w-full flex-col bg-tnv11-bg font-tnv11-sans text-tnv11-ink antialiased selection:bg-rose-500 selection:text-white">
<input type="radio" name="tnv11" id="tnv11-t1" class="sr-only" aria-label="Home" checked><input type="radio" name="tnv11" id="tnv11-t2" class="sr-only" aria-label="Messages"><input type="radio" name="tnv11" id="tnv11-t3" class="sr-only" aria-label="Explore"><input type="radio" name="tnv11" id="tnv11-t4" class="sr-only" aria-label="Saved"><input type="radio" name="tnv11" id="tnv11-t5" class="sr-only" aria-label="Profile">
<header class="flex h-16 items-center justify-between border-b border-white/[0.07] bg-tnv11-surface px-6 sm:px-10">
<span class="text-lg font-bold tracking-[-0.01em]">Nova<span class="text-rose-400">App</span></span>
<span class="grid size-9 place-items-center rounded-full bg-linear-135 from-violet-500 to-rose-500 text-xs font-bold">AK</span>
</header>
<main class="grid flex-1 place-items-center px-6 pt-14 pb-40 text-center [&_code]:rounded [&_code]:bg-white/[0.08] [&_code]:px-1.5 [&_code]:font-tnv11-mono [&_code]:text-[0.85em] [&>section]:hidden [&>section]:max-w-sm [&>section]:flex-col [&>section]:items-center [&>section]:gap-4 [&>section]:transition-[opacity,translate] [&>section]:duration-300 [&>section]:starting:translate-y-2 [&>section]:starting:opacity-0 [&_h2]:text-3xl [&_h2]:font-bold [&_h2]:tracking-[-0.02em] [&_p]:text-[15px]/[1.65] [&_p]:text-tnv11-mut [&_[data-ic]]:mb-2 [&_[data-ic]]:grid [&_[data-ic]]:size-[72px] [&_[data-ic]]:place-items-center [&_[data-ic]]:rounded-[22px] [&_[data-ic]_svg]:size-8">
<section class="group-has-[#tnv11-t1:checked]/root:flex"><span data-ic class="bg-rose-500/12 text-rose-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg></span><h2>Home</h2><p>Your personalised feed. The active tab expands into a labelled pill and its icon springs with <code>scale-110</code>.</p></section>
<section class="group-has-[#tnv11-t2:checked]/root:flex"><span data-ic class="bg-cyan-500/12 text-cyan-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg></span><h2>Messages</h2><p>3 unread conversations. The badge on the dock disappears now that you've opened this tab.</p></section>
<section class="group-has-[#tnv11-t3:checked]/root:flex"><span data-ic class="bg-emerald-500/12 text-emerald-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg></span><h2>Explore</h2><p>Trending content. The search icon tilts as it activates, a small touch of personality per tab.</p></section>
<section class="group-has-[#tnv11-t4:checked]/root:flex"><span data-ic class="bg-amber-500/12 text-amber-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg></span><h2>Saved</h2><p>Everything you've bookmarked. Each tab owns a colour, so you always know where you are.</p></section>
<section class="group-has-[#tnv11-t5:checked]/root:flex"><span data-ic class="bg-violet-500/12 text-violet-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span><h2>Profile</h2><p>Your account and settings. Use the arrow keys on the dock: it's a real radio group.</p></section>
</main>
<nav aria-label="App" class="fixed bottom-6 left-1/2 z-20 flex -translate-x-1/2 items-center gap-1 rounded-full border border-white/[0.08] bg-tnv11-surface/85 p-2 shadow-[0_16px_40px_-8px_rgb(0_0_0/0.6)] backdrop-blur-xl group-has-[input:focus-visible]/root:ring-2 group-has-[input:focus-visible]/root:ring-white/40 [&_label]:flex [&_label]:h-12 [&_label]:cursor-pointer [&_label]:items-center [&_label]:gap-2 [&_label]:rounded-full [&_label]:px-3.5 [&_label]:text-tnv11-mut [&_label]:transition-[background-color,color] [&_label]:duration-300 [&_label]:select-none [&_label:hover]:text-white [&_svg]:size-[22px] [&_svg]:transition-[scale,rotate] [&_svg]:duration-300 [&_svg]:ease-[cubic-bezier(.34,1.56,.64,1)] [&_[data-t]]:max-w-0 [&_[data-t]]:overflow-hidden [&_[data-t]]:text-[13px] [&_[data-t]]:font-bold [&_[data-t]]:whitespace-nowrap [&_[data-t]]:opacity-0 [&_[data-t]]:transition-[max-width,opacity] [&_[data-t]]:duration-300 motion-reduce:[&_*]:transition-none">
<label for="tnv11-t1" class="group-has-[#tnv11-t1:checked]/root:bg-rose-500/15 group-has-[#tnv11-t1:checked]/root:text-rose-400 group-has-[#tnv11-t1:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg><span data-t>Home</span></label>
<label for="tnv11-t2" class="relative group-has-[#tnv11-t2:checked]/root:bg-cyan-500/15 group-has-[#tnv11-t2:checked]/root:text-cyan-400 group-has-[#tnv11-t2:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span data-t>Messages</span><span aria-label="3 unread" class="absolute top-1.5 left-7 grid size-[18px] place-items-center rounded-full border-2 border-tnv11-surface bg-rose-500 text-[10px] font-bold text-white transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] group-has-[#tnv11-t2:checked]/root:scale-0">3</span></label>
<label for="tnv11-t3" class="group-has-[#tnv11-t3:checked]/root:bg-emerald-500/15 group-has-[#tnv11-t3:checked]/root:text-emerald-400 group-has-[#tnv11-t3:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t3:checked]/root:[&_svg]:-rotate-12 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg><span data-t>Explore</span></label>
<label for="tnv11-t4" class="group-has-[#tnv11-t4:checked]/root:bg-amber-500/15 group-has-[#tnv11-t4:checked]/root:text-amber-400 group-has-[#tnv11-t4:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t4:checked]/root:[&_svg]:fill-current group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg><span data-t>Saved</span></label>
<label for="tnv11-t5" class="group-has-[#tnv11-t5:checked]/root:bg-violet-500/15 group-has-[#tnv11-t5:checked]/root:text-violet-400 group-has-[#tnv11-t5:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span data-t>Profile</span></label>
</nav>
</div><div class="tnv-11 group/root flex min-h-svh w-full flex-col bg-tnv11-bg font-tnv11-sans text-tnv11-ink antialiased selection:bg-rose-500 selection:text-white">
<input type="radio" name="tnv11" id="tnv11-t1" class="sr-only" aria-label="Home" checked><input type="radio" name="tnv11" id="tnv11-t2" class="sr-only" aria-label="Messages"><input type="radio" name="tnv11" id="tnv11-t3" class="sr-only" aria-label="Explore"><input type="radio" name="tnv11" id="tnv11-t4" class="sr-only" aria-label="Saved"><input type="radio" name="tnv11" id="tnv11-t5" class="sr-only" aria-label="Profile">
<header class="flex h-16 items-center justify-between border-b border-white/[0.07] bg-tnv11-surface px-6 sm:px-10">
<span class="text-lg font-bold tracking-[-0.01em]">Nova<span class="text-rose-400">App</span></span>
<span class="grid size-9 place-items-center rounded-full bg-linear-135 from-violet-500 to-rose-500 text-xs font-bold">AK</span>
</header>
<main class="grid flex-1 place-items-center px-6 pt-14 pb-40 text-center [&_code]:rounded [&_code]:bg-white/[0.08] [&_code]:px-1.5 [&_code]:font-tnv11-mono [&_code]:text-[0.85em] [&>section]:hidden [&>section]:max-w-sm [&>section]:flex-col [&>section]:items-center [&>section]:gap-4 [&>section]:transition-[opacity,translate] [&>section]:duration-300 [&>section]:starting:translate-y-2 [&>section]:starting:opacity-0 [&_h2]:text-3xl [&_h2]:font-bold [&_h2]:tracking-[-0.02em] [&_p]:text-[15px]/[1.65] [&_p]:text-tnv11-mut [&_[data-ic]]:mb-2 [&_[data-ic]]:grid [&_[data-ic]]:size-[72px] [&_[data-ic]]:place-items-center [&_[data-ic]]:rounded-[22px] [&_[data-ic]_svg]:size-8">
<section class="group-has-[#tnv11-t1:checked]/root:flex"><span data-ic class="bg-rose-500/12 text-rose-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg></span><h2>Home</h2><p>Your personalised feed. The active tab expands into a labelled pill and its icon springs with <code>scale-110</code>.</p></section>
<section class="group-has-[#tnv11-t2:checked]/root:flex"><span data-ic class="bg-cyan-500/12 text-cyan-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg></span><h2>Messages</h2><p>3 unread conversations. The badge on the dock disappears now that you've opened this tab.</p></section>
<section class="group-has-[#tnv11-t3:checked]/root:flex"><span data-ic class="bg-emerald-500/12 text-emerald-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg></span><h2>Explore</h2><p>Trending content. The search icon tilts as it activates, a small touch of personality per tab.</p></section>
<section class="group-has-[#tnv11-t4:checked]/root:flex"><span data-ic class="bg-amber-500/12 text-amber-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg></span><h2>Saved</h2><p>Everything you've bookmarked. Each tab owns a colour, so you always know where you are.</p></section>
<section class="group-has-[#tnv11-t5:checked]/root:flex"><span data-ic class="bg-violet-500/12 text-violet-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span><h2>Profile</h2><p>Your account and settings. Use the arrow keys on the dock: it's a real radio group.</p></section>
</main>
<nav aria-label="App" class="fixed bottom-6 left-1/2 z-20 flex -translate-x-1/2 items-center gap-1 rounded-full border border-white/[0.08] bg-tnv11-surface/85 p-2 shadow-[0_16px_40px_-8px_rgb(0_0_0/0.6)] backdrop-blur-xl group-has-[input:focus-visible]/root:ring-2 group-has-[input:focus-visible]/root:ring-white/40 [&_label]:flex [&_label]:h-12 [&_label]:cursor-pointer [&_label]:items-center [&_label]:gap-2 [&_label]:rounded-full [&_label]:px-3.5 [&_label]:text-tnv11-mut [&_label]:transition-[background-color,color] [&_label]:duration-300 [&_label]:select-none [&_label:hover]:text-white [&_svg]:size-[22px] [&_svg]:transition-[scale,rotate] [&_svg]:duration-300 [&_svg]:ease-[cubic-bezier(.34,1.56,.64,1)] [&_[data-t]]:max-w-0 [&_[data-t]]:overflow-hidden [&_[data-t]]:text-[13px] [&_[data-t]]:font-bold [&_[data-t]]:whitespace-nowrap [&_[data-t]]:opacity-0 [&_[data-t]]:transition-[max-width,opacity] [&_[data-t]]:duration-300 motion-reduce:[&_*]:transition-none">
<label for="tnv11-t1" class="group-has-[#tnv11-t1:checked]/root:bg-rose-500/15 group-has-[#tnv11-t1:checked]/root:text-rose-400 group-has-[#tnv11-t1:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg><span data-t>Home</span></label>
<label for="tnv11-t2" class="relative group-has-[#tnv11-t2:checked]/root:bg-cyan-500/15 group-has-[#tnv11-t2:checked]/root:text-cyan-400 group-has-[#tnv11-t2:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span data-t>Messages</span><span aria-label="3 unread" class="absolute top-1.5 left-7 grid size-[18px] place-items-center rounded-full border-2 border-tnv11-surface bg-rose-500 text-[10px] font-bold text-white transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] group-has-[#tnv11-t2:checked]/root:scale-0">3</span></label>
<label for="tnv11-t3" class="group-has-[#tnv11-t3:checked]/root:bg-emerald-500/15 group-has-[#tnv11-t3:checked]/root:text-emerald-400 group-has-[#tnv11-t3:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t3:checked]/root:[&_svg]:-rotate-12 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg><span data-t>Explore</span></label>
<label for="tnv11-t4" class="group-has-[#tnv11-t4:checked]/root:bg-amber-500/15 group-has-[#tnv11-t4:checked]/root:text-amber-400 group-has-[#tnv11-t4:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t4:checked]/root:[&_svg]:fill-current group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg><span data-t>Saved</span></label>
<label for="tnv11-t5" class="group-has-[#tnv11-t5:checked]/root:bg-violet-500/15 group-has-[#tnv11-t5:checked]/root:text-violet-400 group-has-[#tnv11-t5:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span data-t>Profile</span></label>
</nav>
</div>@import "tailwindcss";
@theme {
--color-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}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-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}<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=Urbanist:wght@400..800&family=JetBrains+Mono:wght@400;500&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=Urbanist:wght@400..800&family=JetBrains+Mono:wght@400;500&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Twenty-five
#nav-11-tN:checked ~ .dock .item:nth-child(N) …rules becamegroup-has-[#tnv11-tN:checked]/root:utilities on the label they style, with shared dock styling declared once on the<nav>. - The 4px indicator dot and its markup were removed: the expanding pill is the indicator.
- Logic fix from the CSS original: the unread badge only appeared while Messages was open; it now shows until you open Messages, then pops away.
- Accessibility upgrade: radios were
display:none; they are now an arrow-key radio group with a visible focus ring, and muted icons rose from zinc-500 to zinc-400 (7.7:1).
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 CSS Mobile Bottom Navigation Bar with Animated Icons
Source: https://codefronts.com/navigation/tailwind-css-navigation-menus/tailwind-css-mobile-bottom-navigation-bar/
An app-style floating dock: five icons, and the active one expands into a tinted pill that reveals its label, each tab in its own colour. Icons spring on selection, a Messages badge shows until you open Messages, and the page above swaps with a starting: fade. Radios behind the scenes mean arrow keys work. Zero JavaScript.
## HTML
```html
<div class="tnv-11 group/root flex min-h-svh w-full flex-col bg-tnv11-bg font-tnv11-sans text-tnv11-ink antialiased selection:bg-rose-500 selection:text-white">
<input type="radio" name="tnv11" id="tnv11-t1" class="sr-only" aria-label="Home" checked><input type="radio" name="tnv11" id="tnv11-t2" class="sr-only" aria-label="Messages"><input type="radio" name="tnv11" id="tnv11-t3" class="sr-only" aria-label="Explore"><input type="radio" name="tnv11" id="tnv11-t4" class="sr-only" aria-label="Saved"><input type="radio" name="tnv11" id="tnv11-t5" class="sr-only" aria-label="Profile">
<header class="flex h-16 items-center justify-between border-b border-white/[0.07] bg-tnv11-surface px-6 sm:px-10">
<span class="text-lg font-bold tracking-[-0.01em]">Nova<span class="text-rose-400">App</span></span>
<span class="grid size-9 place-items-center rounded-full bg-linear-135 from-violet-500 to-rose-500 text-xs font-bold">AK</span>
</header>
<main class="grid flex-1 place-items-center px-6 pt-14 pb-40 text-center [&_code]:rounded [&_code]:bg-white/[0.08] [&_code]:px-1.5 [&_code]:font-tnv11-mono [&_code]:text-[0.85em] [&>section]:hidden [&>section]:max-w-sm [&>section]:flex-col [&>section]:items-center [&>section]:gap-4 [&>section]:transition-[opacity,translate] [&>section]:duration-300 [&>section]:starting:translate-y-2 [&>section]:starting:opacity-0 [&_h2]:text-3xl [&_h2]:font-bold [&_h2]:tracking-[-0.02em] [&_p]:text-[15px]/[1.65] [&_p]:text-tnv11-mut [&_[data-ic]]:mb-2 [&_[data-ic]]:grid [&_[data-ic]]:size-[72px] [&_[data-ic]]:place-items-center [&_[data-ic]]:rounded-[22px] [&_[data-ic]_svg]:size-8">
<section class="group-has-[#tnv11-t1:checked]/root:flex"><span data-ic class="bg-rose-500/12 text-rose-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg></span><h2>Home</h2><p>Your personalised feed. The active tab expands into a labelled pill and its icon springs with <code>scale-110</code>.</p></section>
<section class="group-has-[#tnv11-t2:checked]/root:flex"><span data-ic class="bg-cyan-500/12 text-cyan-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg></span><h2>Messages</h2><p>3 unread conversations. The badge on the dock disappears now that you've opened this tab.</p></section>
<section class="group-has-[#tnv11-t3:checked]/root:flex"><span data-ic class="bg-emerald-500/12 text-emerald-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg></span><h2>Explore</h2><p>Trending content. The search icon tilts as it activates, a small touch of personality per tab.</p></section>
<section class="group-has-[#tnv11-t4:checked]/root:flex"><span data-ic class="bg-amber-500/12 text-amber-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg></span><h2>Saved</h2><p>Everything you've bookmarked. Each tab owns a colour, so you always know where you are.</p></section>
<section class="group-has-[#tnv11-t5:checked]/root:flex"><span data-ic class="bg-violet-500/12 text-violet-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span><h2>Profile</h2><p>Your account and settings. Use the arrow keys on the dock: it's a real radio group.</p></section>
</main>
<nav aria-label="App" class="fixed bottom-6 left-1/2 z-20 flex -translate-x-1/2 items-center gap-1 rounded-full border border-white/[0.08] bg-tnv11-surface/85 p-2 shadow-[0_16px_40px_-8px_rgb(0_0_0/0.6)] backdrop-blur-xl group-has-[input:focus-visible]/root:ring-2 group-has-[input:focus-visible]/root:ring-white/40 [&_label]:flex [&_label]:h-12 [&_label]:cursor-pointer [&_label]:items-center [&_label]:gap-2 [&_label]:rounded-full [&_label]:px-3.5 [&_label]:text-tnv11-mut [&_label]:transition-[background-color,color] [&_label]:duration-300 [&_label]:select-none [&_label:hover]:text-white [&_svg]:size-[22px] [&_svg]:transition-[scale,rotate] [&_svg]:duration-300 [&_svg]:ease-[cubic-bezier(.34,1.56,.64,1)] [&_[data-t]]:max-w-0 [&_[data-t]]:overflow-hidden [&_[data-t]]:text-[13px] [&_[data-t]]:font-bold [&_[data-t]]:whitespace-nowrap [&_[data-t]]:opacity-0 [&_[data-t]]:transition-[max-width,opacity] [&_[data-t]]:duration-300 motion-reduce:[&_*]:transition-none">
<label for="tnv11-t1" class="group-has-[#tnv11-t1:checked]/root:bg-rose-500/15 group-has-[#tnv11-t1:checked]/root:text-rose-400 group-has-[#tnv11-t1:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg><span data-t>Home</span></label>
<label for="tnv11-t2" class="relative group-has-[#tnv11-t2:checked]/root:bg-cyan-500/15 group-has-[#tnv11-t2:checked]/root:text-cyan-400 group-has-[#tnv11-t2:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span data-t>Messages</span><span aria-label="3 unread" class="absolute top-1.5 left-7 grid size-[18px] place-items-center rounded-full border-2 border-tnv11-surface bg-rose-500 text-[10px] font-bold text-white transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] group-has-[#tnv11-t2:checked]/root:scale-0">3</span></label>
<label for="tnv11-t3" class="group-has-[#tnv11-t3:checked]/root:bg-emerald-500/15 group-has-[#tnv11-t3:checked]/root:text-emerald-400 group-has-[#tnv11-t3:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t3:checked]/root:[&_svg]:-rotate-12 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg><span data-t>Explore</span></label>
<label for="tnv11-t4" class="group-has-[#tnv11-t4:checked]/root:bg-amber-500/15 group-has-[#tnv11-t4:checked]/root:text-amber-400 group-has-[#tnv11-t4:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t4:checked]/root:[&_svg]:fill-current group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg><span data-t>Saved</span></label>
<label for="tnv11-t5" class="group-has-[#tnv11-t5:checked]/root:bg-violet-500/15 group-has-[#tnv11-t5:checked]/root:text-violet-400 group-has-[#tnv11-t5:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span data-t>Profile</span></label>
</nav>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}
```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 CSS Mobile Bottom Navigation Bar with Animated Icons
Source: https://codefronts.com/navigation/tailwind-css-navigation-menus/tailwind-css-mobile-bottom-navigation-bar/
An app-style floating dock: five icons, and the active one expands into a tinted pill that reveals its label, each tab in its own colour. Icons spring on selection, a Messages badge shows until you open Messages, and the page above swaps with a starting: fade. Radios behind the scenes mean arrow keys work. Zero JavaScript.
## HTML
```html
<div class="tnv-11 group/root flex min-h-svh w-full flex-col bg-tnv11-bg font-tnv11-sans text-tnv11-ink antialiased selection:bg-rose-500 selection:text-white">
<input type="radio" name="tnv11" id="tnv11-t1" class="sr-only" aria-label="Home" checked><input type="radio" name="tnv11" id="tnv11-t2" class="sr-only" aria-label="Messages"><input type="radio" name="tnv11" id="tnv11-t3" class="sr-only" aria-label="Explore"><input type="radio" name="tnv11" id="tnv11-t4" class="sr-only" aria-label="Saved"><input type="radio" name="tnv11" id="tnv11-t5" class="sr-only" aria-label="Profile">
<header class="flex h-16 items-center justify-between border-b border-white/[0.07] bg-tnv11-surface px-6 sm:px-10">
<span class="text-lg font-bold tracking-[-0.01em]">Nova<span class="text-rose-400">App</span></span>
<span class="grid size-9 place-items-center rounded-full bg-linear-135 from-violet-500 to-rose-500 text-xs font-bold">AK</span>
</header>
<main class="grid flex-1 place-items-center px-6 pt-14 pb-40 text-center [&_code]:rounded [&_code]:bg-white/[0.08] [&_code]:px-1.5 [&_code]:font-tnv11-mono [&_code]:text-[0.85em] [&>section]:hidden [&>section]:max-w-sm [&>section]:flex-col [&>section]:items-center [&>section]:gap-4 [&>section]:transition-[opacity,translate] [&>section]:duration-300 [&>section]:starting:translate-y-2 [&>section]:starting:opacity-0 [&_h2]:text-3xl [&_h2]:font-bold [&_h2]:tracking-[-0.02em] [&_p]:text-[15px]/[1.65] [&_p]:text-tnv11-mut [&_[data-ic]]:mb-2 [&_[data-ic]]:grid [&_[data-ic]]:size-[72px] [&_[data-ic]]:place-items-center [&_[data-ic]]:rounded-[22px] [&_[data-ic]_svg]:size-8">
<section class="group-has-[#tnv11-t1:checked]/root:flex"><span data-ic class="bg-rose-500/12 text-rose-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg></span><h2>Home</h2><p>Your personalised feed. The active tab expands into a labelled pill and its icon springs with <code>scale-110</code>.</p></section>
<section class="group-has-[#tnv11-t2:checked]/root:flex"><span data-ic class="bg-cyan-500/12 text-cyan-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg></span><h2>Messages</h2><p>3 unread conversations. The badge on the dock disappears now that you've opened this tab.</p></section>
<section class="group-has-[#tnv11-t3:checked]/root:flex"><span data-ic class="bg-emerald-500/12 text-emerald-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg></span><h2>Explore</h2><p>Trending content. The search icon tilts as it activates, a small touch of personality per tab.</p></section>
<section class="group-has-[#tnv11-t4:checked]/root:flex"><span data-ic class="bg-amber-500/12 text-amber-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg></span><h2>Saved</h2><p>Everything you've bookmarked. Each tab owns a colour, so you always know where you are.</p></section>
<section class="group-has-[#tnv11-t5:checked]/root:flex"><span data-ic class="bg-violet-500/12 text-violet-400"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span><h2>Profile</h2><p>Your account and settings. Use the arrow keys on the dock: it's a real radio group.</p></section>
</main>
<nav aria-label="App" class="fixed bottom-6 left-1/2 z-20 flex -translate-x-1/2 items-center gap-1 rounded-full border border-white/[0.08] bg-tnv11-surface/85 p-2 shadow-[0_16px_40px_-8px_rgb(0_0_0/0.6)] backdrop-blur-xl group-has-[input:focus-visible]/root:ring-2 group-has-[input:focus-visible]/root:ring-white/40 [&_label]:flex [&_label]:h-12 [&_label]:cursor-pointer [&_label]:items-center [&_label]:gap-2 [&_label]:rounded-full [&_label]:px-3.5 [&_label]:text-tnv11-mut [&_label]:transition-[background-color,color] [&_label]:duration-300 [&_label]:select-none [&_label:hover]:text-white [&_svg]:size-[22px] [&_svg]:transition-[scale,rotate] [&_svg]:duration-300 [&_svg]:ease-[cubic-bezier(.34,1.56,.64,1)] [&_[data-t]]:max-w-0 [&_[data-t]]:overflow-hidden [&_[data-t]]:text-[13px] [&_[data-t]]:font-bold [&_[data-t]]:whitespace-nowrap [&_[data-t]]:opacity-0 [&_[data-t]]:transition-[max-width,opacity] [&_[data-t]]:duration-300 motion-reduce:[&_*]:transition-none">
<label for="tnv11-t1" class="group-has-[#tnv11-t1:checked]/root:bg-rose-500/15 group-has-[#tnv11-t1:checked]/root:text-rose-400 group-has-[#tnv11-t1:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t1:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><path d="M9 22V12h6v10"/></svg><span data-t>Home</span></label>
<label for="tnv11-t2" class="relative group-has-[#tnv11-t2:checked]/root:bg-cyan-500/15 group-has-[#tnv11-t2:checked]/root:text-cyan-400 group-has-[#tnv11-t2:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t2:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span data-t>Messages</span><span aria-label="3 unread" class="absolute top-1.5 left-7 grid size-[18px] place-items-center rounded-full border-2 border-tnv11-surface bg-rose-500 text-[10px] font-bold text-white transition-[scale] duration-300 ease-[cubic-bezier(.34,1.56,.64,1)] group-has-[#tnv11-t2:checked]/root:scale-0">3</span></label>
<label for="tnv11-t3" class="group-has-[#tnv11-t3:checked]/root:bg-emerald-500/15 group-has-[#tnv11-t3:checked]/root:text-emerald-400 group-has-[#tnv11-t3:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t3:checked]/root:[&_svg]:-rotate-12 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t3:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg><span data-t>Explore</span></label>
<label for="tnv11-t4" class="group-has-[#tnv11-t4:checked]/root:bg-amber-500/15 group-has-[#tnv11-t4:checked]/root:text-amber-400 group-has-[#tnv11-t4:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t4:checked]/root:[&_svg]:fill-current group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t4:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 000-7.78z"/></svg><span data-t>Saved</span></label>
<label for="tnv11-t5" class="group-has-[#tnv11-t5:checked]/root:bg-violet-500/15 group-has-[#tnv11-t5:checked]/root:text-violet-400 group-has-[#tnv11-t5:checked]/root:[&_svg]:scale-110 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:max-w-24 group-has-[#tnv11-t5:checked]/root:[&_[data-t]]:opacity-100"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" aria-hidden="true"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span data-t>Profile</span></label>
</nav>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tnv11-bg: #0f0f13;
--color-tnv11-bg: oklch(0.17 0.008 285);
--color-tnv11-surface: #18181f;
--color-tnv11-surface: oklch(0.21 0.012 285);
--color-tnv11-ink: #f5f5fa;
--color-tnv11-ink: oklch(0.97 0.005 285);
--color-tnv11-mut: #a1a1aa;
--color-tnv11-mut: oklch(0.705 0.015 286);
--font-tnv11-sans: 'Urbanist', system-ui, sans-serif;
--font-tnv11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tnv-11 {
width: 100%;
min-height: 100svh;
}
```How this works
Expanding pills beat dots. The CSS original showed every label at all times and marked the active tab with a 4px dot. Here the selected tab grows into a labelled pill, which is easier to read at a glance and leaves the dock compact:
<label for="tnv11-t1" class="group-has-[#tnv11-t1:checked]/root:bg-rose-500/15">
<svg class="group-has-[#tnv11-t1:checked]/root:scale-110">
<span class="max-w-0 opacity-0
group-has-[#tnv11-t1:checked]/root:max-w-24 …">Home</span>Labels never leave the DOM, so screen readers always hear ‘Home’, ‘Messages’, even when the text is folded to zero width.
Make it yours
- Always-visible labels: drop the
max-w-0 opacity-0pair. - Edge-to-edge bar: replace the floating dock with
inset-x-0 bottom-0 rounded-none pb-[env(safe-area-inset-bottom)]. - Single accent: replace the five palette colours with one token.
Gotchas — read before shipping
- Fixed docks cover content; keep
pb-36(or more) on the scrolling area. - Add
pb-[env(safe-area-inset-bottom)]on iOS so the dock clears the home indicator. - Radios announce as ‘radio button, 1 of 5’, which is accurate for a tab switcher without JS.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() required; starting: page fades are progressive.