Light

Header

A top-level navigation bar with logo, breadcrumbs, search, and user actions.

Spec · from metadataOpen in Figma ↗

When to use

  • Top-level app header bar across all TimelyCare platforms
  • Need breadcrumb + search + actions + avatar layout
  • Responsive header that adapts desktop (3-column) to mobile (hamburger + stacked)
  • Composing with Sidebar for full app shell

When not to use

  • Marketing/landing page hero sections — use a custom layout instead
  • Page-level section headers — use a semantic <header> with heading elements
  • Navigation-only bar — use NavigationMenu directly

Anti-patterns

Avoid<Header>
  <a href="/home">Home</a>
  <a href="/about">About</a>
</Header>
Prefer<Header>
  <HeaderLeft>
    <Breadcrumb>...</Breadcrumb>
  </HeaderLeft>
</Header>

Header is a structural shell, not a navigation component. Put nav content inside Breadcrumb, NavigationMenu, or Sidebar.

Avoid<Header>
  <div className="flex justify-between w-full">...</div>
</Header>
Prefer<Header>
  <HeaderLeft>...</HeaderLeft>
  <HeaderCenter>...</HeaderCenter>
  <HeaderRight>...</HeaderRight>
</Header>

Use the provided slot sub-components instead of custom flex layouts. They handle responsive behavior and consistent spacing.

Avoid<Header className="h-20 bg-[#19518B]">
Prefer<Header>

Don't override the header height (h-16) or use arbitrary colors. The header uses bg-card and border-b from the token system.

Accessibility

  • Required ARIAaria-label on HeaderMenuButton (auto-provided)
  • Min touch target48px
  • Screen readerHeader uses semantic <header> element. Mobile menu button announces expanded/collapsed state via aria-expanded.

Token bindings

TokenCategoryUsage
card / card-foregroundcolorHeader background and text
bordercolorBottom border
4 (16px) / 6 (24px)spacingHorizontal padding (mobile / desktop)
2 (8px)spacingGap between header items

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

ElementDesktopMobile
Header height64px (h-16)56px (h-14)
Avatar size40×40px (size-10)40×40px
Icon button size28×28px (size-7)36×36px (size-9)
Search input width300pxHidden (icon only)
Mobile nav width300px

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-Care as the current page — not Home > 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

BreakpointLayoutMenu State
desktopFull navigation barAlways visible
mobileCollapsed with hamburgeropen / 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

StateGhost VariantPrimary Variant
Defaultbg-transparentbg-primary text-primary-foreground
Hoverbg-accentbg-primary/90
Pressedbg-accent scale-95bg-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 and aria-current="page" on the current item
  • Add aria-label to <nav> for navigation sections in mobile menu
  • Ensure mobile menu toggle has aria-expanded and aria-controls
  • Consider adding a skip-to-content link

Gotchas

ProblemSolution
Menu doesn't close on navAdd onOpenChange handler to Sheet
Breadcrumbs overflowUse truncate or hide on mobile
Search not responsiveHide input on mobile, show icon trigger
Logo not centered mobileUse absolute positioning with left-1/2 -translate-x-1/2
Mobile nav icons too smallUse size-6 (24px) for mobile nav icons vs size-4 (16px) desktop
Avatar not matching designUse rounded-xl (14px radius) not rounded-full, font-normal not font-medium (see Avatar)
Header border misaligned with sidebarApply 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 tallOmit image on mobile — show only title, description, and action links

See Also


Last updated: February 20, 2026