Skip to main content

NavBar

What this component provides:

  • Main site navigation with internal page links
  • External links to documentation and GitHub (opens in new tab)
  • Integrated theme switching via ThemeSwitch component
  • Responsive hamburger menu for mobile screens
  • Accessible tooltips on all interactive elements
  • Smooth animations and transitions
  • Backdrop overlay for mobile menu dismissal

Dependencies

  • lucide-react - For navigation icons (Home, Users, Info, Github, Menu, X, SquareArrowOutUpRight)
  • react-router-dom - For client-side routing via Link and useLocation
  • @components/GlassCard - Glass morphism container styling
  • @components/ThemeSwitch - Theme toggle button
  • @components/Tooltip - Accessible tooltips

Basic Usage

import NavBar from '@components/NavBar';

export default function App() {
return (
<div>
<NavBar />
<main>{/* Your page content */}</main>
</div>
);
}

The component renders a sticky navigation bar at the top of the page that:

  • Displays the Img2Num logo linking to the home page
  • Shows navigation links for internal pages (Home, Credits, About)
  • Shows external links to documentation and GitHub
  • Includes a theme toggle switch
  • Collapses to a hamburger menu on mobile

Props

This component accepts no props. All navigation links are defined internally via constants:

ConstantPurpose
INTERNAL_LINKSArray of internal route definitions
EXTERNAL_LINKSArray of external URL definitions
{
path: '/', // Route path
label: 'Home', // Display text
icon: Home, // lucide-react icon component
tooltip: 'Go to the home page' // Tooltip text
}
{
href: 'https://github.com/...', // Full URL
label: 'GitHub', // Display text
icon: Github, // lucide-react icon component
tooltip: 'Open the project on GitHub'
}

Styling

The component uses CSS modules with the following key classes:

ClassPurpose
navbarMain container with sticky positioning
logoLogo link with hover effects
logoIconLogo image with hover rotation animation
menuToggleMobile hamburger/close button
backdropFull-screen overlay for mobile menu dismissal
navListNavigation links container
navLinkIndividual navigation link styling
activeApplied to the currently active route link
externalIconSmall icon indicating external links
themeToggleContainer for the theme switch

CSS Variables Used

The component relies on these CSS custom properties:

VariablePurpose
--navbar-menu-z-indexZ-index for navbar (100)
--navbar-menu-backdrop-z-indexZ-index for backdrop (99)
--spacing-sm, --spacing-mdSpacing values
--radius-mdBorder radius
--color-text, --color-primaryText and accent colors
--glass-bg, --glass-borderGlass morphism styling

Responsive Behavior

The NavBar adapts to screen size:

Desktop (> 768px)

  • All navigation links displayed horizontally
  • Menu toggle hidden
  • Backdrop hidden

Mobile (≤ 768px)

  • Navigation links hidden by default
  • Hamburger menu toggle visible
  • Click toggle to reveal dropdown menu
  • Backdrop covers screen behind menu
  • Staggered animation on menu items
  • Click outside (on backdrop) to close

Accessibility

The component follows accessibility best practices:

FeatureImplementation
Semantic HTMLUses <nav> element with role="menubar"
Menu toggle ARIAaria-expanded, aria-controls, aria-label
Menu itemsrole="menuitem" on all links
Backdroparia-hidden="true" (not for screen readers)
External linkstarget="_blank" with rel="noopener noreferrer"
Keyboard supportFull keyboard navigation support
TooltipsAll interactive elements have descriptive tooltips
Focus managementBrowser default focus indicators

Examples

Standard Usage (in App.jsx)

import { Routes, Route } from 'react-router-dom';
import NavBar from '@components/NavBar';
import Home from '@pages/Home';
import About from '@pages/About';
import Credits from '@pages/Credits';

export default function App() {
return (
<>
<NavBar />
<main>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/credits" element={<Credits />} />
</Routes>
</main>
</>
);
}

The currently active route is automatically highlighted using useLocation:

// In NavBar.jsx
const { pathname } = useLocation();

// Applied conditionally
className={`${styles.navLink} ${pathname === path ? styles.active : ''}`}

How It Works

  1. Initialization: Component initializes with isOpen state for mobile menu
  2. Location tracking: useLocation hook tracks current route for active styling
  3. Menu toggle: Click handler toggles isOpen state and updates ARIA attributes
  4. Menu close: closeMenu function called on:
    • Logo click
    • Any navigation link click
    • Backdrop click
  5. Rendering: Conditionally renders backdrop only when menu is open

Implementation

NavBar.jsx
import { useState } from 'react';
import { Home, Users, Info, Github, SquareArrowOutUpRight, Menu, X } from 'lucide-react';
import { Link, useLocation } from 'react-router-dom';
import styles from './NavBar.module.css';
import GlassCard from '@components/GlassCard';
import ThemeSwitch from '@components/ThemeSwitch';
import Tooltip from '@components/Tooltip';

const INTERNAL_LINKS = [
{ path: '/', label: 'Home', icon: Home, tooltip: 'Go to the home page' },
{ path: '/credits', label: 'Credits', icon: Users, tooltip: 'View project credits' },
{ path: '/about', label: 'About', icon: Info, tooltip: 'Learn more about Img2Num' },
];

const EXTERNAL_LINKS = [
{ href: 'https://ryan-millard.github.io/Img2Num/info/', label: 'Docs', icon: Info, tooltip: 'View documentation' },
{
href: 'https://github.com/Ryan-Millard/Img2Num',
label: 'GitHub',
icon: Github,
tooltip: 'Open the project on GitHub',
},
];

export default function NavBar() {
const [isOpen, setIsOpen] = useState(false);
const { pathname } = useLocation();
const closeMenu = () => setIsOpen(false);

return (
<GlassCard as="nav" className={styles.navbar}>
{/* Logo, Toggle, Backdrop, Navigation Links, Theme Switch */}
</GlassCard>
);
}

Visual States

StateAppearance
DefaultTransparent background with glass blur
Link hoverBackground highlight, slight lift animation
Link activeBrown background, primary color border
Mobile closedOnly logo and hamburger visible
Mobile openFull menu dropdown with backdrop overlay

Animation Details

ElementAnimation
Logo iconRotates 12° and scales 1.08x on hover
Nav linksTranslate up 2px on hover
External iconMoves diagonally on hover
Mobile menuFades in with translateY animation
Menu itemsStaggered fade + slide animation (30ms delay each)
BackdropSubtle blur effect

Testing

The NavBar component has comprehensive tests covering:

  • Rendering of logo, navigation links, and theme switch
  • Active state styling based on current route
  • Mobile menu open/close interactions
  • Backdrop appearance and click handling
  • Accessibility attributes and roles
  • External link security attributes
  • Icon rendering

See NavBar Testing for detailed test documentation.

  • ThemeSwitch - The theme toggle included in NavBar
  • Tooltip - Tooltips used on all interactive elements
  • GlassCard - Glass morphism container wrapper