Skip to content

Navbar

This page explains how the global navbar is currently implemented in 3AM.

Main implementation file: src/components/navbar.ts.

What this navbar handles

Desktop mega menus (hover/focus open behavior).

Mobile menu open/close behavior under breakpoint.

Scroll-aware shell state (is-scrolled, is-hidden).

Active link sync with current route.

Deferred media loading inside mega panels.

State model

Navbar keeps explicit internal state fields:

  • activeMenu
  • isMobileMenuOpen
  • isScrolled
  • isHidden
  • currentPath

Why this is good

Explicit state fields make behavior easier to reason about than scattered DOM-only checks.

Interaction pattern

Problematic Example (fragile)

text
Attach events in many places with ad-hoc selectors.
No centralized state.
Difficult to debug focus and hover edge cases.
text
Centralized handlers + explicit state fields.
Lifecycle-safe listener registration via cleanup bag.
DOM classes/datasets are derived from state.

Deferred media behavior in mega menus

Navbar lazily upgrades media inside mega panels when a menu opens for the first time.

This prevents loading all mega-menu media on initial page paint.

Problematic Example (eager)

html
<img src="/heavy-image.webp" />
html
<img src="/assets/shared/placeholder.png" data-deferred-src="/heavy-image.webp" />

When to edit navbar vs elsewhere

Edit navbar.ts when behavior or structure changes.

Edit src/styles/components/navbar.css when visual behavior changes.

Edit Button or MediaCard components when shared API behavior changes across navbar and other features.

Related docs: Ready Components, Guidelines, Contributing.

High-impact area

Navbar is mounted globally. A bug here affects every route. Always validate keyboard focus, mobile menu behavior, and active-link logic before PR.

MDN references