Back to ShowcaseFull Canvas Preview
Navigation

Pill Navigation Header

An ultra-minimal modular pill-shaped header component (PillHeader / DarkModeHeader) featuring floating glassmorphic pill elements, customizable action buttons, adaptive light/dark theme toggle, and floating mobile menu container.

ReactTailwind CSSNext.jsTheme SwitcherPill Layout

Live Component Preview

dark-mode-header.tsx
"use client";
import * as React from "react";
import Link from "next/link";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "@/components/theme-provider";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
const logoMark =
"https://www.figma.com/api/mcp/asset/97aa703a-9be3-453a-854e-ad260e5f72aa.svg";
export type PillHeaderProps = {
variant?: "desktop" | "compact";
className?: string;
homeHref?: string;
onMenuClick?: () => void;
};
// Backwards compatibility export alias
export type DarkModeHeaderProps = PillHeaderProps;
const frame =
"border border-border/80 bg-background/75 backdrop-blur-xl shadow-[0_10px_30px_rgba(15,23,42,0.06)] transition-all duration-200";
export function PillHeader({
className,
homeHref = "/",
onMenuClick,
}: PillHeaderProps) {
const { theme, setTheme } = useTheme();
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
const toggleTheme = () => {
setTheme(theme === "dark" ? "light" : "dark");
};
return (
<header
className={cn(
"inline-flex h-[52px] items-center justify-center text-foreground antialiased relative mt-2",
"gap-[8px] md:gap-[16px]",
"rounded-full",
className,
)}
>
<Link
href={homeHref}
aria-label="UDX home"
className={cn(
"flex h-12 w-12 shrink-0 items-center justify-center",
"rounded-full",
"border border-border/80 bg-background/85 shadow-[0_8px_20px_rgba(15,23,42,0.05)] transition-all duration-200 hover:bg-accent/60",
)}
>
<svg className="h-5 w-5 shrink-0 text-foreground" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="18" height="18" rx="5" className="fill-primary/10 stroke-primary" strokeWidth="1.5" />
<path d="M7 8H17M7 12H17M7 16H13" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</Link>
<nav
aria-label="Primary navigation"
className={cn(
"hidden md:flex h-12 items-center justify-center gap-1 rounded-full border border-border/80 bg-background/75 px-2 py-1.5 shadow-[0_8px_20px_rgba(15,23,42,0.04)] backdrop-blur-xl",
)}
>
{[
{ label: "Home", href: "#" },
{ label: "About", href: "#about" },
{ label: "Product", href: "#product" },
].map((item, index) => (
<Link
key={item.label}
href={item.href}
className={cn(
"rounded-full px-3 py-2 text-[13px] font-medium leading-none transition-all duration-200",
index === 0
? "bg-accent text-foreground shadow-sm"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
)}
>
{item.label}
</Link>
))}
</nav>
<div className="flex h-[52px] items-center">
<button
type="button"
onClick={toggleTheme}
aria-label={`Switch to ${theme === "dark" ? "light" : "dark"} mode`}
className={cn(
"relative z-10 -mr-px flex h-12 w-12 shrink-0 items-center justify-center",
"rounded-full",
"border border-border/80 bg-background/80 text-foreground shadow-[0_8px_18px_rgba(15,23,42,0.04)] transition-all duration-200 hover:bg-accent/60",
)}
>
{theme === "dark" ? (
<Sun className="h-4 w-4 stroke-[1.8]" />
) : (
<Moon className="h-4 w-4 stroke-[1.8]" />
)}
</button>
<div
className={cn(
"hidden md:flex relative z-10 h-12 items-center gap-2 justify-center rounded-full border border-border/80 bg-background/80 px-2 py-1.5 shadow-[0_8px_18px_rgba(15,23,42,0.04)] backdrop-blur-xl",
)}
>
<Button
render={<Link href="#" className="rounded-[inherit]" />}
>
Get Started
</Button>
<Button
variant="outline"
render={<Link href="#" className="rounded-[inherit]" />}
>
Login
</Button>
</div>
<button
type="button"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Open navigation menu"
className={cn(
"flex md:hidden h-12 w-12 items-center justify-center",
"rounded-full",
"border border-border/80 bg-background/80 text-foreground transition-all duration-200 hover:bg-accent/60 shadow-[0_8px_18px_rgba(15,23,42,0.04)]",
"relative z-10 -mr-px",
)}
>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="h-4 w-4">
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 9h16.5m-16.5 6.75h16.5" />
</svg>
</button>
</div>
{isMobileMenuOpen && (
<div className="absolute top-[calc(100%+10px)] left-0 w-full min-w-[220px] md:hidden rounded-[22px] border border-border/80 bg-card/95 p-4 shadow-[0_20px_45px_rgba(15,23,42,0.08)] backdrop-blur-xl flex flex-col gap-3 z-40">
<nav className="flex flex-col gap-1.5">
{[
{ label: "Home", href: "#" },
{ label: "About", href: "#about" },
{ label: "Product", href: "#product" },
].map((item) => (
<Link
key={item.label}
href={item.href}
className="rounded-xl px-3 py-2 text-[14px] font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
>
{item.label}
</Link>
))}
</nav>
<div className="mt-1 flex flex-col gap-2 border-t border-border/60 pt-3">
<Button className="w-full rounded-full" render={<Link href="#" className="w-full" />}>
Get Started
</Button>
<Button variant="outline" className="w-full rounded-full" render={<Link href="#" className="w-full" />}>
Login
</Button>
</div>
</div>
)}
</header>
);
}
export const DarkModeHeader = PillHeader;
export default PillHeader;