Custom component — not a shadcn primitive
Import
import { Header } from "@/components/custom/header"
Props
interface HeaderProps {
breadcrumbs?: BreadcrumbItem[]
searchPlaceholder?: string
onSearch?: (query: string) => void
actions?: React.ReactNode
user?: { name: string; avatar?: string; initials?: string }
showInput?: boolean
className?: string
}
interface BreadcrumbItem {
label: string
href?: string
dropdown?: { label: string; href: string }[]
}
Dimensions
| Element | Desktop | Mobile |
|---|---|---|
| Header height | 64px (h-16) | 56px (h-14) |
| Avatar size | 40×40px (size-10) | 40×40px |
| Icon button size | 28×28px (size-7) | 36×36px (size-9) |
| Search input width | 300px | Hidden (icon only) |
| Mobile nav width | — | 300px |
Header + Sidebar Alignment
The header and sidebar share the same height for their top sections. Both use h-16 (64px) with border-b border-border so the bottom strokes align perfectly at the horizontal seam.
Critical: Apply border-b directly on the same element that has h-16 — do not wrap in an extra container, as this offsets the border by the container's own border-width.
{/* Sidebar header — h-16 with border-b */}
<div className="h-16 flex items-center border-b border-border px-6">
<Logo />
</div>
{/* Page header — same h-16 with border-b, no wrapper */}
<header className="flex h-16 items-center gap-3 px-4 border-b border-border">
<Breadcrumb className="flex-1">{/* ... */}</Breadcrumb>
<Avatar />
</header>
Breadcrumb Behavior
The header uses the Breadcrumb component (ShadCN pattern) for navigation context.
Navigation model
- Default state: Breadcrumb displays "Home" as the current page.
- Sidebar nav click: The selected nav item becomes the breadcrumb (e.g. clicking "Self-Care" shows
Self-Careas the current page — notHome > Self-Care). Top-level sidebar items are the first-level breadcrumb. - Sub-page navigation: Deeper pages append to the breadcrumb trail (e.g.
Self-Care > Breathwork). - Logo click: Clicking the sidebar logo resets navigation to the home page, which resets the breadcrumb to "Home".
Breadcrumb structure (ShadCN)
<nav aria-label="Breadcrumb">
<ol className="flex items-center gap-1.5">
<li>
<BreadcrumbLink href="/self-care">Self-Care</BreadcrumbLink>
</li>
<li>
<ChevronRight className="size-[15px] text-muted-foreground" />
</li>
<li>
<BreadcrumbPage>Breathwork</BreadcrumbPage>
</li>
</ol>
</nav>
Breakpoints
| Breakpoint | Layout | Menu State |
|---|---|---|
desktop | Full navigation bar | Always visible |
mobile | Collapsed with hamburger | open / closed |
Responsive Behavior
- Desktop shows: breadcrumbs, optional search input, optional action buttons, avatar
- Mobile closed shows: hamburger menu (left), centered logo, search icon + action icons (right)
- Mobile closed also shows: breadcrumbs below header bar in separate row
- Mobile open: Sheet overlay from left with full navigation
Icon Button States
| State | Ghost Variant | Primary Variant |
|---|---|---|
| Default | bg-transparent | bg-primary text-primary-foreground |
| Hover | bg-accent | bg-primary/90 |
| Pressed | bg-accent scale-95 | bg-primary/80 scale-95 |
Mobile Menu Structure
┌─────────────────────────────┐
│ [Logo] [X] │ ← Header with close button
├─────────────────────────────┤
│ 🤲 Self-Care │
│ 🛡️ Provider Care │
│ 💬 Community │
│ 🏆 Success Coaching │
│ ✉️ Messages │
├─────────────────────────────┤ ← Separator
│ ❓ Help Center │
│ ⚙️ Account │
│ ↩️ Log Out │
├─────────────────────────────┤
│ ┌─────────────────────────┐ │
│ │ New Feature! │ │ ← Optional promo card (no image)
│ │ Description text... │ │
│ │ [View] [Dismiss] │ │
│ └─────────────────────────┘ │
└─────────────────────────────┘
Note: The mobile promo card omits images to fit within available space. Only title, description, and action links are shown.
Common Patterns
Desktop Header
<header className="flex h-16 items-center gap-4 px-4 bg-sidebar border-b border-border">
{/* Breadcrumbs — fills available space */}
<Breadcrumb className="flex-1">
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbPage>Home</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
{/* Optional: Search input — fixed width */}
<div className="relative w-[300px] shrink-0">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" />
<Input placeholder="I'm seeking resources for..." className="pl-9" />
</div>
{/* Optional: Action buttons */}
<Button variant="outline">Button</Button>
<Button>Button</Button>
{/* Avatar — size 10, rounded shape (see avatar.md for full spec) */}
<Avatar className="size-10 rounded-xl">
<AvatarImage src="/user.jpg" alt="User" />
<AvatarFallback className="font-normal font-sans">CN</AvatarFallback>
</Avatar>
</header>
Mobile Header (Closed)
<header className="border-b border-border">
{/* Main bar */}
<div className="flex h-14 items-center justify-between px-3 relative">
<Button variant="ghost" size="icon" className="size-9">
<Menu className="size-5" />
</Button>
{/* Centered logo */}
<Logo variant="default" width={120} height={44} className="absolute left-1/2 -translate-x-1/2" />
<div className="flex items-center gap-3">
<Button variant="ghost" size="icon" className="size-9">
<Search className="size-5" />
</Button>
<Button size="icon" className="size-9">
<Zap className="size-5" />
</Button>
</div>
</div>
{/* Breadcrumbs row */}
<div className="px-4 py-4">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/settings">Settings</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Profile details</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
</header>
Mobile Menu (Open)
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" size="icon"><Menu className="size-5" /></Button>
</SheetTrigger>
<SheetContent side="left" className="w-[300px] p-4">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<Logo variant="default" width={120} height={44} />
<SheetClose asChild>
<Button variant="secondary" size="icon" className="size-9">
<X className="size-5" />
</Button>
</SheetClose>
</div>
{/* Primary navigation */}
<nav className="space-y-1 p-2" aria-label="Main navigation">
<NavItem icon={HandHeart} label="Self-Care" />
<NavItem icon={ShieldUser} label="Provider Care" />
<NavItem icon={MessageSquareText} label="Community" />
<NavItem icon={Trophy} label="Success Coaching" />
<NavItem icon={Mail} label="Messages" />
</nav>
<Separator className="my-4" />
{/* Secondary navigation */}
<nav className="space-y-1 p-2" aria-label="Secondary navigation">
<NavItem icon={CircleHelp} label="Help Center" />
<NavItem icon={UserCog} label="Account" />
<NavItem icon={LogOut} label="Log Out" />
</nav>
{/* Optional promo card at bottom (no image on mobile) */}
<Card className="absolute bottom-6 left-4 right-4">
<CardHeader>
<CardTitle>New Feature!</CardTitle>
<CardDescription>Check out our new Breathwork Tool</CardDescription>
</CardHeader>
<CardFooter className="justify-between">
<Button variant="link" size="sm">View</Button>
<Button variant="link" size="sm">Dismiss</Button>
</CardFooter>
</Card>
</SheetContent>
</Sheet>
Navigation Item
<a href={item.href} className="flex items-center gap-2 p-2 text-sm font-semibold text-muted-foreground rounded-md hover:bg-accent">
<item.icon className="size-6" />
{item.label}
</a>
Accessibility
- Custom component — requires manual a11y implementation
- Use
<header>landmark element for the container - Breadcrumbs use
<nav aria-label="Breadcrumb">with<ol>list structure andaria-current="page"on the current item - Add
aria-labelto<nav>for navigation sections in mobile menu - Ensure mobile menu toggle has
aria-expandedandaria-controls - Consider adding a skip-to-content link
Gotchas
| Problem | Solution |
|---|---|
| Menu doesn't close on nav | Add onOpenChange handler to Sheet |
| Breadcrumbs overflow | Use truncate or hide on mobile |
| Search not responsive | Hide input on mobile, show icon trigger |
| Logo not centered mobile | Use absolute positioning with left-1/2 -translate-x-1/2 |
| Mobile nav icons too small | Use size-6 (24px) for mobile nav icons vs size-4 (16px) desktop |
| Avatar not matching design | Use rounded-xl (14px radius) not rounded-full, font-normal not font-medium (see Avatar) |
| Header border misaligned with sidebar | Apply border-b on the same h-16 element — don't wrap in an extra container |
| Breadcrumbs show "Home > Section" | Top-level nav items replace "Home" as the breadcrumb, not append to it |
| Mobile promo card too tall | Omit image on mobile — show only title, description, and action links |
See Also
- Related Components: Sidebar (side navigation with logo-click-to-home), Breadcrumb (breadcrumb primitives), Navigation Menu (nav links)
- Patterns: Layouts — Page layout patterns
Last updated: February 20, 2026