Navigation Bar (Responsive) with Mobile Menu
A responsive navigation bar component with mobile hamburger menu, sticky scroll behavior, optional transparent-to-solid transition, and first-class dropdown support. Supports marketing (logo + links + CTA) and app (user menu, notifications) variants.
Structure Specification
Component Hierarchy
The navbar consists of a Navbar Container that holds a Logo/Brand Section, Navigation Links with Dropdown Panels (desktop), Mobile Menu Toggle Button, Action Buttons (CTA or User Menu), and a Mobile Menu Dialog. The Mobile Menu Dialog contains Navigation Links (with accordion sections for items with children) and Action Buttons.
The navbar structure flows as: Navbar contains Logo, NavLinks (desktop with dropdown toggles/panels), MobileToggle, and Actions. The MobileMenu (dialog) contains NavLinks (with accordion behavior) and Actions.
Detailed Component Specifications
1. Navbar Component
Goal: Provide a responsive navigation bar that adapts to screen sizes, supports sticky/transparent behavior, and includes accessible mobile menu and dropdown navigation.
Anatomy Slots:
logo- Brand logo/image/textnavLinks- Navigation links (desktop visible, mobile in dialog)mobileToggle- Hamburger menu button (mobile only)actions- CTA button(s) or user menu (desktop)dropdownPanels- Desktop dropdown panels (disclosure pattern)mobileMenu- Modal dialog for mobile navigation
Dimensions:
- Desktop: Full width, height 64-80px (default: 72px)
- Mobile: Full width, height 56-64px (default: 60px)
- Sticky: Fixed at top when scrolling
- Max-width: Optional container constraint (e.g., 1400px)
States:
variant(enum: "marketing" | "app", default: "marketing") - Navbar style variantsticky(boolean, default: true) - Whether navbar is sticky on scroll (default true for both variants)transparent(boolean, default: false) - Transparent background (becomes solid on scroll; recommended only for marketing variant when background contrast is sufficient)mobileMenuOpen(boolean, default: false) - Whether mobile menu dialog is visiblescrolled(boolean, computed) - Whether page has scrolled beyond threshold (used for transparent→solid and sticky elevation)activeLink(string) - Current active navigation link ID/route (syncs with router/URL)openDropdownId(string, default: "") - ID of currently open desktop dropdown (prefer single open dropdown at a time)mobileExpandedItemIds(array, default: []) - IDs of expanded accordion sections inside mobile dialog (allow multiple expanded)
Elements:
Logo/Brand Section
- Height: 40-48px (logo image/text)
- Padding: 16-24px from left edge
- Clickable: Links to home page
- Responsive: May shrink on mobile or show icon-only variant
Navigation Links (Desktop)
- Horizontal layout with gap: 24-32px between links
- Font size: 14-16px, medium weight (500-600)
- Active state: Underline, color change, or background highlight
- Hover state: Subtle color change or underline
- Hidden on mobile (< 768px)
- Dropdown Support: Items with children open disclosure dropdown panels on click (no hover-only behavior)
- Dropdown Toggle: Button with
aria-haspopup="true",aria-expanded, andaria-controls - Dropdown Panel: Container for links (disclosure pattern; avoid
role="menu"unless fully implementing ARIA menu semantics)
Mobile Menu Toggle
- Size: 40px × 40px icon button
- Icon: Hamburger (☰) when closed, close (×) when open
- Position: Right-aligned, 16px from edge
- Visible: Only on mobile/tablet (< 1024px)
- ARIA:
aria-label="Toggle menu",aria-expanded="true/false",aria-controls="mobile-menu"
Action Buttons/User Menu
- Marketing Variant: Primary CTA button (e.g., "Get Started", "Sign Up")
- Button size: 32-40px height, padding 12-16px horizontal
- Position: Right-aligned, 16-24px from edge
- App Variant: User menu dropdown with avatar
- Avatar: 36-40px circle
- Dropdown: Opens below avatar on click
- Contains: Profile, Settings, Logout links
- Optional: Notifications button with badge
Desktop Dropdown Panels
- Pattern: Disclosure pattern (button controls a panel of links)
- Position: Below dropdown toggle, aligned to toggle or left edge
- Z-index: 80 (dropdowns from tokens)
- Behavior: Opens on toggle click, closes on outside click or Escape
- Focus: Does not trap focus; uses normal Tab order
- ARIA: Toggle has
aria-haspopup="true",aria-expanded,aria-controls; panel has matchingid - Animation: 180ms open, 150ms close (opacity, transform, visibility)
- Note: Avoid
role="menu"/role="menuitem"unless fully implementing ARIA menu button pattern with arrow-key semantics
Mobile Menu Dialog
- Modal dialog overlay when open (uses
role="dialog"witharia-modal="true") - Background: White (light) or dark neutral (dark mode)
- Position: Fixed, full width, slides from top or left
- Z-index: 60 (mobileMenu from tokens)
- Contains: Navigation links (vertical stack, items with children render as accordion sections) and action buttons
- Backdrop: Optional dark overlay behind menu (z-index: 50)
- Animation: Slide-in from top/left (300ms), fade backdrop (200ms)
- Accordion Sections: Items with children expand/collapse without closing the dialog
Behavior:
- Sticky positioning: Fixed at top when
sticky=trueand user scrolls (default: true) - Transparent→Solid: Background transitions from transparent to solid on scroll (when
transparent=true; marketing variant only) - Mobile menu: Opens/closes on toggle button click
- Mobile menu: Closes on backdrop click, Escape key, or link click
- Mobile accordion: Items with children expand/collapse as accordion sections (does not close dialog)
- Focus trap: Focus trapped within mobile menu dialog when open
- Focus restoration: Returns focus to toggle button when menu closes
- Body scroll lock: Body scroll locked when mobile menu is open (restore on close)
- Desktop dropdowns: Open on toggle click, close on outside click or Escape (disclosure pattern)
- Desktop dropdown focus: Does not trap focus; uses normal Tab order; Escape restores focus to toggle
- Active link: Highlights current page/route using project's routing solution
- Keyboard navigation: Full keyboard support for all interactive elements
Responsive Breakpoints
Mobile (< 768px)
- Layout: Logo left, hamburger menu right
- Navigation: Hidden, accessible via mobile menu dialog
- Dropdowns: Items with children render as accordion sections inside the dialog
- Actions: Shown in mobile menu
- Height: 60px
- Mobile Menu: Modal dialog overlay; full-screen or slide-in panel
Tablet (768px - 1023px)
- Layout: Logo left, hamburger menu right
- Navigation: Default to mobile menu dialog pattern
- Dropdowns: Items with children still behave as accordion sections inside the dialog
- Actions: May be in navbar if space allows; otherwise in mobile menu
- Height: 72px
- Default: Use mobile menu dialog pattern (same as mobile breakpoint)
Desktop (≥ 1024px)
- Layout: Logo left, nav links center/left, actions right
- Navigation: Horizontal nav links visible
- Dropdowns: Items with children open disclosure dropdown panels on click (no hover-only behavior)
- Actions: Visible in navbar
- Height: 72px
- Mobile Menu: Hidden (hamburger button hidden)
Interaction Patterns
Sticky Scroll Behavior
- User scrolls down page
- If
sticky=true, navbar becomes fixed at top - If
transparent=true, background transitions from transparent to solid - Shadow appears for depth (optional)
- Navbar remains visible during scroll
Mobile Menu Open
- User clicks hamburger button
- Mobile menu overlay appears with animation
- Focus moves to first link in menu
- Body scroll is locked
- Backdrop appears (optional)
- Focus is trapped within menu
Mobile Menu Close
- User clicks close button, backdrop, or Escape key
- Mobile menu closes with animation
- Focus returns to hamburger button
- Body scroll is unlocked
- Backdrop fades out
Desktop Dropdown Open
- User clicks dropdown toggle button
- Dropdown panel appears below toggle with animation (180ms)
aria-expandedupdates totrueon toggle- Panel receives focus (first link) or focus stays on toggle (product-specific)
- Other open dropdowns close automatically (single open at a time)
Desktop Dropdown Close
- User clicks outside dropdown, clicks toggle again, or presses Escape
- Dropdown panel closes with animation (150ms)
aria-expandedupdates tofalseon toggle- Focus returns to toggle button (on Escape)
- Outside click does not restore focus
Mobile Accordion Toggle
- User clicks accordion toggle inside mobile dialog
- Accordion section expands/collapses with animation
aria-expandedupdates on accordion toggle- Mobile dialog remains open (does not close)
- Focus remains within the dialog
Active Link Highlighting
- Current page/route is detected using project's routing solution
- Active link is visually highlighted (underline, color change, or background)
aria-current="page"is set on active link- Highlight persists on page reload
- Route changes update active link and may close open overlays (product-specific)
Accessibility Requirements
WCAG 2.1 Compliance (Level AA Target)
This navbar component should meet WCAG 2.1 Level AA standards. Key requirements:
- 2.1.1 Keyboard: All navbar controls operable via keyboard; focus trapped within mobile dialog while open.
- 2.1.2 No Keyboard Trap: Escape closes mobile dialog and dropdowns; no keyboard trap beyond intended modal focus trap.
- 2.4.3 Focus Order: Logical focus order; focus returns to correct toggle when overlays close.
- 2.4.7 Focus Visible: Visible focus indicators for all interactive elements.
- 4.1.2 Name, Role, Value: Correct ARIA roles, names, and relationships.
Keyboard Navigation
Tab Order:
- Logo → Nav Links (desktop, including dropdown toggles) → Actions → Mobile Toggle (mobile)
- Within mobile dialog: Links → Accordion toggles → Actions → Close button
- Desktop dropdown panels: Do not trap focus; use normal Tab order
Implementation:
- Tab cycles through focusable elements
- Shift+Tab cycles backwards
- Escape closes mobile dialog when open; otherwise closes open desktop dropdown
- Escape restores focus to the corresponding toggle
- Enter/Space activates links and buttons
Focus Management:
- On Mobile Dialog Open: Move focus to first focusable element inside dialog (often first nav link)
- On Mobile Dialog Close: Return focus to menu toggle button
- On Desktop Dropdown Open: Focus may stay on toggle or move to first link (product-specific)
- On Desktop Dropdown Close (Escape): Restore focus to dropdown toggle
- On Desktop Dropdown Close (Outside Click): Focus does not change
- Mobile Accordion: Focus remains within dialog when toggling accordion sections
- Focus Visible: Clear focus indicators (2px solid outline, 2px offset)
ARIA Attributes
Required ARIA Attributes:
Navbar Element:
<nav role="navigation" aria-label="Main navigation">Mobile Menu Toggle:
<button id="navbar-menu-toggle" aria-label="Toggle menu" aria-expanded="false" aria-controls="navbar-mobile-menu">Mobile Menu:
<div id="navbar-mobile-menu" role="dialog" aria-modal="true" aria-labelledby="navbar-menu-toggle" aria-hidden="true"> <nav aria-label="Main navigation"> <!-- Navigation links --> </nav> </div>Note: Mobile menu uses
role="dialog"witharia-modal="true"because it's a modal overlay with focus trap. Inside the dialog, include<nav aria-label="Main navigation">for the links.Active Navigation Link:
<a href="/current-page" aria-current="page">Current Page</a>User Menu Button:
<button aria-label="User menu" aria-haspopup="true" aria-expanded="false" aria-controls="user-dropdown">Desktop Dropdown Toggle:
<button aria-haspopup="true" aria-expanded="false" aria-controls="dropdown-panel-products"> Products </button>Desktop Dropdown Panel:
<div id="dropdown-panel-products"> <a href="/products/feature1">Feature 1</a> <a href="/products/feature2">Feature 2</a> </div>Note: Prefer disclosure semantics (button controls a panel of links). Avoid
role="menu"unless fully implementing ARIA menu keyboard semantics.Mobile Accordion Toggle:
<button aria-expanded="false" aria-controls="accordion-panel-products"> Products </button>Mobile Accordion Panel:
<div id="accordion-panel-products"> <a href="/products/feature1">Feature 1</a> <a href="/products/feature2">Feature 2</a> </div>Notifications Button:
<button aria-label="Notifications: 3 unread"
aria-haspopup="true"
aria-expanded="false">
<span class="notifications-badge" aria-label="3 unread">3</span>
</button>
Dynamic ARIA Updates:
- Update
aria-expandedon mobile menu toggle when dialog opens/closes - Update
aria-expandedon desktop dropdown toggles when panels open/close - Update
aria-expandedon mobile accordion toggles when sections expand/collapse - Update
aria-hiddenon mobile menu (true when closed; false/omitted when open) - Update
aria-modal="true"on mobile menu when open - Make background content inert/aria-hidden while mobile dialog is open (use
inertif available, or applyaria-hiddento main content) - Update
aria-current="page"on active navigation link - Update
aria-labelon notifications button to include count
Screen Reader Support
Announcements:
- Mobile menu state changes (via
aria-expandedand focus management) - Active page changes (via
aria-current="page")
Labels:
- All icon-only buttons must have descriptive
aria-label - Logo image must have descriptive
alttext - Navigation links should have clear, descriptive text
Screen Reader Only Text (sr-only class):
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
Focus Visible Styles
Implementation:
button:focus-visible,
a:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
/* Fallback for older browsers */
button:focus,
a:focus,
[tabindex]:focus {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
Accessibility Implementation Checklist
When implementing this navbar, ensure:
- [ ] All buttons have
aria-labelor visible text - [ ] Mobile menu uses
role="dialog"+aria-modal="true"and contains<nav aria-label="Main navigation"> - [ ] Mobile menu toggle has id,
aria-expanded, andaria-controls - [ ] Focus trap is active only while the mobile dialog is open; focus restores to the menu toggle on close
- [ ] Background content is inert/aria-hidden while the mobile dialog is open
- [ ] Body scroll lock is applied when mobile dialog is open and cleaned up on close
- [ ] Desktop dropdown toggles have
aria-expanded+aria-controls; Escape closes and restores focus - [ ] Mobile dropdowns are accordions with
aria-expanded+aria-controls; expanding does not close the dialog - [ ] Active link uses
aria-current="page"correctly - [ ] All interactive elements have visible focus indicators
- [ ] Prefers-reduced-motion reduces durations and avoids transform motion where possible
Design System Specifications
Important: The design specifications below are tool-agnostic and should be implemented using your project's chosen styling approach (Tailwind, CSS Modules, styled-components, Chakra UI, Material-UI, SCSS, etc.). The styling examples in the "Code Implementation Patterns" section show how to apply these design values, but these specifications are the source of truth for the design.
Color Guidelines
Navbar Background
- Light (Default): White (
#ffffff) or very light gray (#f9fafb) - Light (Transparent):
rgba(255, 255, 255, 0.95)withbackdrop-filter: blur(8px) - Light (Scrolled): White (
#ffffff) with shadow - Dark (Default):
#1a1a1aor#0f172a - Dark (Transparent):
rgba(26, 26, 26, 0.95)withbackdrop-filter: blur(8px) - Dark (Scrolled):
#1a1a1awith shadow
Navigation Links
- Text (Light): Dark gray (
#111827,#1f2937) or black (#000000) - Text (Dark):
#e0e0e0or#f1f5f9 - Hover (Light): Primary color or darker gray
- Hover (Dark): Primary color or lighter gray
- Active (Light): Primary color with underline or background
- Active (Dark): Primary color with underline or background
- Contrast: Ensure 4.5:1 contrast ratio minimum (WCAG AA)
Logo
- Text/Icon: Match navigation link colors or brand color
- Hover: Subtle opacity change or color shift
Mobile Menu
- Background (Light): White (
#ffffff) - Background (Dark):
#1a1a1aor#0f172a - Backdrop:
rgba(0, 0, 0, 0.5)torgba(0, 0, 0, 0.75) - Links: Match navbar link colors
Action Buttons
- Primary CTA: Use project's primary button style
- User Menu: Match navbar text colors
- Notifications Badge: Red (
#ef4444,#dc2626) or primary color
Typography
- Font Family: Use project's font stack (typically: system-ui, -apple-system, sans-serif or custom font)
- Navigation Links: 14-16px, medium weight (500-600)
- Logo: 18-24px, bold (700) or use logo image
- CTA Button: 14-16px, semibold (600)
- Line Height: 1.25 for headings, 1.5 for body text
Spacing System
Use consistent spacing scale (4px, 8px, 12px, 16px, 24px, 32px, 48px, 64px) or your project's spacing system:
- Navbar Padding: 16-24px horizontal (desktop), 16px (mobile)
- Logo Padding: 16-24px from left edge
- Nav Links Gap: 24-32px between links (desktop)
- Actions Padding: 16-24px from right edge
- Mobile Menu Padding: 24px on all sides
- Mobile Menu Link Gap: 16-24px vertical between links
Shadows & Elevation
Use subtle shadows for depth and separation:
- Navbar Shadow (Sticky/Scrolled, Light):
0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06) - Navbar Shadow (Sticky/Scrolled, Dark):
0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2) - Mobile Menu Shadow:
0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)
Border Radius
- Buttons: 6-8px
- Mobile Menu: 0 (full width) or 8-12px if not full-screen
- Avatar: 50% (circle)
- Badges: 12-16px (pill shape)
Visual Hierarchy Principles
- Logo should be clearly visible and clickable
- Navigation links should be easily scannable
- Active link should be clearly highlighted
- CTA button should stand out (marketing variant)
- Mobile menu should be clearly separated from main content
- Focus indicators should be clearly visible
- Transparent→Solid transition should be smooth and noticeable
State Management Considerations
For AI Agents to Implement
State to Track:
mobileMenuOpen: boolean- Whether mobile menu dialog is visible (default: false)scrolled: boolean- Whether page has scrolled beyond threshold (computed from scroll position >tokens.layout.scrollThresholdPx, default: false)activeLink: string- Current active navigation link ID/route (syncs with router/URL)variant: "marketing" | "app"- Navbar style variant (default: "marketing")sticky: boolean- Whether navbar is sticky on scroll (default: true)transparent: boolean- Whether navbar starts transparent (default: false; recommended only for marketing variant)openDropdownId: string- ID of currently open desktop dropdown (default: ""; prefer single open at a time)mobileExpandedItemIds: array- IDs of expanded accordion sections inside mobile dialog (default: []; allow multiple expanded)
State Persistence:
- All state is component-level only (no persistence needed)
activeLinkshould sync with router/URL
SSR/Hydration Considerations
- Mobile menu state: Initialize
mobileMenuOpenasfalseto prevent hydration mismatches - Scroll state: Only access
windowand scroll position after component mount - Implementation: Check
typeof window !== 'undefined'before accessing window object
Critical Implementation Guidelines
Project Detection
Before implementing, AI agents must detect:
- Framework: Identify React/Vue/Angular/Svelte and routing libraries by inspecting package.json and existing components
- Styling System: Detect Tailwind, SCSS, CSS Modules, styled-components, etc. and use ONLY that system
- Design Tokens: Identify existing color systems, spacing scales, and typography from the project
CRITICAL: Use ONLY the detected styling system. Do NOT introduce new styling systems.
Vanilla CSS Detection
CRITICAL: When detecting vanilla CSS in the project, ALWAYS create CSS classes in a stylesheet. NEVER use inline style attributes on HTML elements.
- Define classes like
.navbar,.navbar--sticky,.navbar--transparent,.mobile-menu, etc. in your CSS file - Apply classes via
className/classattributes:<nav class="navbar navbar--sticky"> - Do NOT use:
<nav style="position: fixed"> - This ensures maintainability, reusability, and proper separation of concerns
React Hook Patterns
CRITICAL: When detecting React, extract logic from useEffect hooks into separate custom hooks that do ONE thing each.
- Instead of one
useEffecthandling multiple concerns (scroll listener + mobile menu + focus trap), create separate hooks:useScrollPosition()- Handles scroll position tracking onlyuseMobileMenu()- Handles mobile menu state onlyuseFocusTrap(containerRef, isActive)- Handles focus trapping onlyuseBodyScrollLock(isLocked)- Handles body scroll locking only
- This improves code organization, testability, and reusability
- Each hook should have a single responsibility
Code Implementation Patterns
React Example Pattern
// Suggested component structure
<Navbar
variant="marketing"
sticky={true}
transparent={true}
activeLink={currentRoute}
>
<NavbarLogo href="/">Brand</NavbarLogo>
<NavbarLinks>
<NavLink href="/about" active={currentRoute === '/about'}>About</NavLink>
<NavLink href="/pricing" active={currentRoute === '/pricing'}>Pricing</NavLink>
<NavLink href="/contact" active={currentRoute === '/contact'}>Contact</NavLink>
</NavbarLinks>
<NavbarActions>
<Button variant="primary">Get Started</Button>
</NavbarActions>
<MobileMenuToggle />
<MobileMenu>
<MobileNavLinks />
<MobileActions />
</MobileMenu>
</Navbar>
Angular Example Pattern
<!-- Suggested template structure -->
<nav class="navbar"
[class.navbar--sticky]="isSticky"
[class.navbar--scrolled]="hasScrolled"
role="navigation"
aria-label="Main navigation">
<a class="navbar-logo" href="/">Brand</a>
<ul class="navbar-links" *ngIf="!isMobile">
<li><a href="/about" [attr.aria-current]="currentRoute === '/about' ? 'page' : null">About</a></li>
<li><a href="/pricing" [attr.aria-current]="currentRoute === '/pricing' ? 'page' : null">Pricing</a></li>
</ul>
<button class="mobile-toggle"
*ngIf="isMobile"
(click)="toggleMobileMenu()"
[attr.aria-expanded]="mobileMenuOpen"
aria-label="Toggle menu">
☰
</button>
<div class="mobile-menu"
*ngIf="isMobile && mobileMenuOpen"
[attr.aria-hidden]="!mobileMenuOpen">
<!-- Mobile menu content -->
</div>
</nav>
Vue Example Pattern
<!-- Suggested component structure -->
<template>
<nav class="navbar"
:class="{ 'navbar--sticky': sticky, 'navbar--scrolled': scrolled }"
role="navigation"
aria-label="Main navigation">
<a class="navbar-logo" href="/">Brand</a>
<ul class="navbar-links" v-if="!isMobile">
<li><a href="/about" :aria-current="currentRoute === '/about' ? 'page' : undefined">About</a></li>
<li><a href="/pricing" :aria-current="currentRoute === '/pricing' ? 'page' : undefined">Pricing</a></li>
</ul>
<button class="mobile-toggle"
v-if="isMobile"
@click="toggleMobileMenu"
:aria-expanded="mobileMenuOpen"
aria-label="Toggle menu">
☰
</button>
<Teleport to="body">
<div v-if="isMobile && mobileMenuOpen"
class="mobile-menu"
:aria-hidden="!mobileMenuOpen">
<!-- Mobile menu content -->
</div>
</Teleport>
</nav>
</template>
CSS/Styling Approaches
Note: The examples below show how to implement the design specifications using different styling tools. Always refer to the "Design System Specifications" section above for the authoritative design values, then adapt them to your project's styling approach.
Tailwind CSS Pattern
<!-- Navbar -->
<nav class="fixed top-0 left-0 right-0 z-50 bg-white shadow-sm transition-all duration-300"
:class="{ 'bg-white/95 backdrop-blur-md': transparent && !scrolled, 'bg-white shadow-md': scrolled }">
<div class="container mx-auto flex items-center justify-between h-18 px-6">
<!-- Logo -->
<a href="/" class="text-xl font-bold">Brand</a>
<!-- Desktop Nav Links -->
<ul class="hidden md:flex items-center gap-8">
<li><a href="/about" class="hover:text-primary">About</a></li>
<li><a href="/pricing" class="hover:text-primary">Pricing</a></li>
</ul>
<!-- Mobile Toggle -->
<button class="md:hidden w-10 h-10" aria-label="Toggle menu">☰</button>
<!-- CTA -->
<button class="hidden md:block px-4 py-2 bg-primary text-white rounded">Get Started</button>
</div>
</nav>
Vanilla CSS Pattern
/* CRITICAL: Always create CSS classes, never use inline styles */
/* Apply design system values directly */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 72px;
background: #ffffff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
z-index: 50;
transition: background 300ms, box-shadow 300ms;
}
.navbar--transparent {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(8px);
box-shadow: none;
}
.navbar--scrolled {
background: #ffffff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
}
.navbar-links {
display: flex;
gap: 32px;
list-style: none;
}
.navbar-link {
font-size: 16px;
font-weight: 500;
color: #111827;
text-decoration: none;
transition: color 150ms;
}
.navbar-link:hover {
color: var(--primary-color);
}
.navbar-link.active {
color: var(--primary-color);
text-decoration: underline;
}
.mobile-menu {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #ffffff;
z-index: 50;
padding: 24px;
transform: translateX(-100%);
transition: transform 300ms;
}
.mobile-menu--open {
transform: translateX(0);
}
Material-UI/Chakra Pattern
- Use AppBar component for navbar (Material-UI) or Box with flex layout (Chakra)
- Extend theme with design system color values, spacing scale, and typography settings
- Use theme.transitions for consistent animations matching design system specifications
- Leverage theme breakpoints for responsive behavior
- Customize colors, spacing, and typography to match design system specifications
- Use Drawer component for mobile menu (Material-UI) or Drawer component (Chakra)
Animation Specifications
Sticky Scroll Transition
- Duration: 200-300ms
- Easing:
cubic-bezier(0.4, 0, 0.2, 1)orease-in-out - Properties:
background-color,box-shadow,backdrop-filter - Trigger: Scroll position > threshold (e.g., 20px)
Transparent→Solid Transition
- Duration: 200-300ms
- Easing:
cubic-bezier(0.4, 0, 0.2, 1) - Properties:
- Background: transparent/surface-overlay → surface-solid (use project tokens)
- Shadow: none → elevated shadow (use project tokens)
- Backdrop filter:
blur(8px)→none(optional; prefer tokens)
Mobile Menu Open
- Duration: 250-300ms (from
tokens.motion.mobileMenuOpenMs) - Easing:
cubic-bezier(0.4, 0, 0.2, 1) - Menu: Slide from top/left:
translateX(-100%)→translateX(0)ortranslateY(-100%)→translateY(0) - Backdrop: Fade in:
opacity: 0→opacity: 1(200ms fromtokens.motion.backdropFadeMs)
Mobile Menu Close
- Duration: 250ms (from
tokens.motion.mobileMenuCloseMs) - Easing:
cubic-bezier(0.4, 0, 0.2, 1) - Menu: Slide out:
translateX(0)→translateX(-100%) - Backdrop: Fade out:
opacity: 1→opacity: 0(150ms)
Desktop Dropdown Open
- Duration: 180ms (from
tokens.motion.dropdownOpenMs) - Easing:
cubic-bezier(0.4, 0, 0.2, 1) - Properties:
opacity,transform,visibility - Note: If
prefers-reduced-motionis enabled, avoid transform and reduce durations to ≤100ms
Desktop Dropdown Close
- Duration: 150ms (from
tokens.motion.dropdownCloseMs) - Easing:
cubic-bezier(0.4, 0, 0.2, 1) - Properties:
opacity,transform,visibility - Note: If
prefers-reduced-motionis enabled, avoid transform and reduce durations to ≤100ms
Prefers-Reduced-Motion Support
When prefers-reduced-motion is enabled:
- Disable transform-based motion where possible (avoid translate animations)
- Reduce animation durations to ≤100ms (use
tokens.motion.reducedMotionDurationMs) - Minimize backdrop-filter blur transitions
- Allow essential opacity transitions (≤100ms)
Implementation:
@media (prefers-reduced-motion: reduce) {
.navbar,
.mobile-menu {
animation: none;
transition: opacity 0.1s ease, background-color 0.1s ease;
}
.mobile-menu {
transform: none; /* Disable translateX/translateY animations */
}
.navbar--transparent {
backdrop-filter: none; /* Minimize blur transitions */
}
}
Performance:
- Prefer
transformandopacityfor animations (GPU-accelerated) - Set
will-change: transform, opacityon animating elements - Use
transform3d(0,0,0)to trigger GPU acceleration if needed
Z-Index Layer System
To ensure proper layering of elements:
- Backdrop: 50 (from tokens)
- Mobile Menu: 60 (from tokens)
- Navbar: 70 (from tokens)
- Dropdowns: 80 (from tokens)
- Tooltips: 90 (from tokens)
Implementation Details
Sticky Positioning
When: sticky=true and user scrolls down
How:
- Set
position: fixedwhen scroll position > threshold - Add shadow for depth
- Smooth transition on background/shadow changes
Cleanup: Remove fixed positioning when scrolling back to top (optional, or keep fixed)
Scroll Detection
When: transparent=true or need to track scroll state
How:
- Add scroll event listener (throttled/debounced - recommended:
requestAnimationFrameor ~100ms throttle) - Update
scrolledstate when scroll position > threshold (default: 20px, fromtokens.layout.scrollThresholdPx) - Trigger background/shadow transitions
Cleanup: Remove scroll listener on unmount
Mobile Menu Focus Trap
When: Mobile menu is open
How:
- Use focus-trap library (e.g.,
focus-trapfor React,focus-trap-vuefor Vue) or manual implementation - Identify all focusable elements within mobile menu
- Prevent tabbing outside menu boundaries
- Cycle focus within menu on Tab/Shift+Tab
Cleanup: Remove focus trap on close
Focus Restoration
When: Mobile menu closes (all close paths)
How:
- Store reference to toggle button when menu opens
- Restore focus to toggle button on close
- Handle cases where toggle button no longer exists (fallback to body or first focusable element)
Body Scroll Lock
When: Mobile menu is open
How:
- Set
document.body.style.overflow = 'hidden'(or project-standard utility) - Optional: Preserve scroll position: Use
position: fixedwithtop: -${window.scrollY}pxto prevent jump when locking scroll - iOS handling: If needed, prevent body touchmove scrolling behind the dialog using project-standard approach
Cleanup:
- Restore previous styles on menu close/unmount
Escape Key Handling
When: Mobile menu is open
How:
- Add global keydown listener for Escape key
- Prevent default and stop propagation
- Close menu and restore focus
Cleanup: Remove listener on close
Active Link Detection
When: Page loads or route changes
How:
- Compare current URL/route with navigation link hrefs using project's routing solution
- Set
aria-current="page"on matching link - Apply active styles (underline, color change, background)
- Route changes may close open overlays (product-specific)
Desktop Dropdown Management
When: User interacts with dropdown toggles
How:
- Track
openDropdownIdstate (prefer single open dropdown at a time) - On toggle click: Open if closed, close if open
- On outside click: Close open dropdown
- On Escape: Close dropdown and restore focus to toggle
- Update
aria-expandedon toggle dynamically - Do not trap focus inside dropdown panels (use normal Tab order)
Cleanup: Close dropdowns on unmount or route change (if required)
Mobile Accordion Management
When: User interacts with accordion toggles inside mobile dialog
How:
- Track
mobileExpandedItemIdsarray (allow multiple expanded sections) - On accordion toggle click: Add/remove item ID from array
- Update
aria-expandedon accordion toggle dynamically - Expanding/collapsing does not close the mobile dialog
- Focus remains within the mobile dialog
Edge Cases
Very Long Navigation Labels
- Truncate with ellipsis on mobile
- Show tooltip on hover (desktop)
- Consider icon-only variant for mobile
Many Navigation Links
- Desktop: May need to wrap to second line or use dropdown
- Mobile: Scrollable menu if many links
- Consider grouping links into categories
Rapid Opening/Closing
- Debounce or disable interactions during animation
- Prevent multiple simultaneous open/close operations
Window Resize During Mobile Menu Open
- Close mobile menu when switching to desktop breakpoint
- Re-evaluate breakpoint on resize (debounced)
Very Small Screens
- Further reduce padding/spacing on screens < 320px
- Consider icon-only logo variant
Content Overflow
- Ensure navbar doesn't overflow viewport horizontally
- Mobile menu should handle vertical overflow with scrolling
Common Variations
Marketing Navbar
- Logo + horizontal nav + primary CTA
- Sticky by default
- Optional transparent-on-hero mode (
transparent=true) that becomes solid on scroll - Dropdowns supported for grouped marketing sections
- Simple, clean design
App Navbar
- Logo + nav + notifications + user menu
- Solid background only (
transparentforced false) - Sticky by default
- Dropdowns commonly used for user menu and nav groupings
- More compact, functional design
Minimal Navbar
- Logo + few nav links only
- No CTA button
- Very clean, minimal design
Centered Navbar
- Logo centered, nav links centered below or around logo
- Less common, used for specific design styles
With Search Bar
- Add search input in navbar
- May replace some nav links on mobile
- Search opens modal or expands inline
Testing Checklist
When implementing this navbar, test:
- [ ] Navbar renders correctly on all breakpoints
- [ ] Mobile menu dialog opens and closes via toggle, Escape, backdrop click, and link click
- [ ] Focus is trapped within the mobile dialog while open
- [ ] Focus is restored to the mobile toggle when the dialog closes
- [ ] Body scroll is locked while the mobile dialog is open and restored on close
- [ ] Sticky positioning works correctly when enabled
- [ ] Transparent→Solid transition works on scroll when enabled (marketing only)
- [ ] Active link is highlighted correctly and uses
aria-current="page" - [ ] Desktop dropdown opens/closes on toggle click
- [ ] Desktop dropdown closes on outside click and Escape
- [ ] Escape on desktop dropdown restores focus to the dropdown toggle
- [ ] Desktop dropdown does not trap focus; Tab order is logical
- [ ] Mobile dropdown items render as accordions inside the dialog
- [ ] Mobile accordion expand/collapse updates
aria-expandedand does not close the dialog - [ ] Route changes update active link and close open overlays if required by product rules
- [ ] Window resize closes the mobile dialog when switching to desktop breakpoint
- [ ] Prefers-reduced-motion reduces durations and avoids transform motion where possible
- [ ] All interactive elements have visible focus indicators
- [ ] Screen reader announces dialog state changes and expanded/collapsed states appropriately
- [ ] SSR/hydration safe (no DOM access before mount)
AI Agent Implementation Prompt Template
Use this template when asking an AI agent to implement this navbar:
Implement a responsive Navigation Bar component with mobile hamburger menu as a modal dialog (role="dialog" aria-modal="true") including focus trap, focus restoration, inert background, and body scroll lock. Support sticky scroll behavior and optional transparent-to-solid transition (marketing recommended only). Add dropdown navigation: on desktop, implement disclosure dropdowns (button controlling a panel of links with aria-expanded/aria-controls; avoid role="menu" unless fully implementing ARIA menu semantics). On mobile/tablet, integrate dropdown items as accordion sections inside the dialog (aria-expanded/aria-controls), and expanding must not close the dialog. Close the mobile dialog on Escape/backdrop/link click. Close desktop dropdown on outside click/Escape and restore focus to its toggle. Implement smooth animations and prefers-reduced-motion (reduce durations to <= tokens.motion.reducedMotionDurationMs and avoid transform-based motion where possible). Adapt to {{USER_FRAMEWORK}} and {{USER_STYLING_LIBRARY}}.
Key requirements:
1. Responsive: Desktop shows horizontal nav links; mobile/tablet show hamburger menu dialog
2. Sticky: Fixed at top when scrolling (sticky=true, default)
3. Transparent→Solid: Background transitions on scroll (transparent=true; marketing only)
4. Mobile Menu: Modal dialog overlay with focus trap, inert background, and body scroll lock
5. Desktop Dropdowns: Disclosure pattern (button + panel), no focus trap, Escape restores focus to toggle
6. Mobile Accordions: Items with children expand/collapse inside dialog without closing it
7. Accessibility: ARIA attributes, keyboard navigation, focus management
8. Active Link: Highlights current page/route using project's routing solution
9. Animations: 150-300ms transitions with prefers-reduced-motion support
10. CRITICAL: Use ONLY the detected styling system. If vanilla CSS is detected, create CSS classes in a stylesheet, never use inline style attributes. If React is detected, separate effects into single-concern hooks.
Reference: UI Potion Navigation Bar Component
Additional Resources
Focus Trap Library Examples
React:
import { createFocusTrap } from 'focus-trap';
const trap = createFocusTrap(mobileMenuRef.current, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
returnFocusOnDeactivate: true,
initialFocus: mobileMenuRef.current.querySelector('a') || mobileMenuRef.current,
});
trap.activate();
Vue:
import { createFocusTrap } from 'focus-trap';
const trap = createFocusTrap(mobileMenuRef.value, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
returnFocusOnDeactivate: true,
});
trap.activate();
Body Scroll Lock Library Examples
React:
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
disableBodyScroll(mobileMenuRef.current);
// On close:
enableBodyScroll(mobileMenuRef.current);
Vue:
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
disableBodyScroll(mobileMenuRef.value);
// On close:
enableBodyScroll(mobileMenuRef.value);
Scroll Detection Hook Example (React)
function useScrollPosition(threshold = 20) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const handleScroll = throttle(() => {
setScrolled(window.scrollY > threshold);
}, 100);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [threshold]);
return scrolled;
}
Summary for AI Agents
This navigation bar is a responsive navbar component with mobile menu dialog, sticky positioning (default: true), optional transparent-to-solid transition (marketing variant only), and first-class dropdown support. Key implementation points:
- Structure: Logo, Navigation Links with Dropdown Panels (desktop), Mobile Toggle, Actions (CTA/User Menu), Mobile Menu Dialog with Accordion Sections
- State: Track mobileMenuOpen, scrolled, activeLink, variant, sticky (default: true), transparent (marketing only), openDropdownId (desktop), mobileExpandedItemIds (mobile)
- Responsive: Desktop shows horizontal nav with disclosure dropdowns; mobile/tablet show hamburger menu dialog with accordion sections
- Sticky: Fixed at top when scrolling (default: true for both variants)
- Transparent→Solid: Background transitions on scroll (marketing variant only, when transparent=true)
- Mobile Menu: Modal dialog with focus trap, inert background, body scroll lock, focus restoration, Escape key handling
- Desktop Dropdowns: Disclosure pattern (button + panel), no focus trap, Escape restores focus to toggle, outside click closes
- Mobile Accordions: Items with children expand/collapse inside dialog without closing it
- Accessibility: WCAG AA compliance with proper ARIA attributes (role="dialog", aria-modal="true", disclosure semantics for dropdowns)
- Project Detection: Must detect framework, router, styling system, and design tokens before implementation
- Framework-agnostic: Adapt patterns to any framework's component model
Generate clean, semantic HTML with proper component separation. Use framework-specific state management patterns and CSS methodology as specified by the user. Use ONLY the detected styling system.