Navbar — Svelte
Navbar component — Svelte.
Navbar component
A responsive, accessible navigation bar with dropdown menus, search, and settings. The docs site uses the Astro Navbar in the layout. In a Svelte app, use the same BEM classes and HTML structure; wire open/close and keyboard behavior with Svelte state and event handlers.
Features
- Desktop: Brand, nav links with dropdowns (e.g. Components, Themes), search trigger, settings button. Dropdowns can use a 2-column layout with vertical divider.
- Mobile (≤1024px): Menu toggle (hamburger) on the left; search and settings (icon-only) on the right. Full-width overlay menu when open; mutually exclusive with search.
- Sticky top, full-width border, smooth open/close transitions.
- Full keyboard navigation for dropdowns (Arrow keys, Enter, Space, Escape, Home, End) and ARIA.
- Settings button opens the Settings panel (
window.openSettings()when using the design system scripts).
Key BEM classes and structure
Use these classes so styles apply correctly. Toggle navbar__menu--open on the menu and navbar--menu-open on the root nav for the mobile menu. Use navbar__item--has-dropdown and navbar__submenu for dropdowns; control visibility with a class (e.g. navbar__item--open) or aria-expanded and CSS.
navbar— rootnav; addnavbar--menu-openwhen mobile menu is open.navbar__container— inner wrapper.navbar__brand/navbar__brand-link— logo and home link.navbar__toggle— mobile menu button; setaria-expandedfrom state.navbar__menu— menu container; addnavbar__menu--openwhen open.navbar__item/navbar__item--has-dropdown— item wrapper;--has-dropdownfor items with a submenu.navbar__link— main link or dropdown trigger.navbar__submenu/navbar__submenu--components/navbar__submenu--themes— submenu list and variants.navbar__sublink— submenu link.navbar__settings-btn— settings button.
Minimal structure example
Simplified markup; in practice you’ll add dropdown content, icons, and data attributes for your JS. In your script: let menuOpen = $state(false); let dropdownOpen = $state(false); (or use a single state for which dropdown is open).
<nav class="navbar" class:navbar--menu-open={menuOpen}>
<div class="navbar__container">
<div class="navbar__brand">
<a href="/" class="navbar__brand-link">Site name</a>
</div>
<button
type="button"
class="navbar__toggle"
aria-label="Toggle menu"
aria-expanded={menuOpen}
onclick={() => (menuOpen = !menuOpen)}
>
<span class="navbar__toggle-icon" aria-hidden="true">...</span>
</button>
<div class="navbar__menu" class:navbar__menu--open={menuOpen} role="menu">
<div class="navbar__item navbar__item--has-dropdown">
<button type="button" class="navbar__link" aria-expanded={dropdownOpen} aria-haspopup="true">
Docs
</button>
<ul class="navbar__submenu" role="menu" aria-hidden={!dropdownOpen}>
<li><a href="/docs" class="navbar__sublink">Overview</a></li>
</ul>
</div>
<a href="/search" class="navbar__item">Search</a>
<button type="button" class="navbar__settings-btn" aria-label="Settings" onclick={() => window.openSettings?.()}>
Settings
</button>
</div>
</div>
</nav>Implementing behavior in Svelte
- Mobile menu: Bind
menuOpen(or similar) to the toggle button; addnavbar__menu--opento the menu andnavbar--menu-opento the root when open. On mobile, close search when opening the menu if your layout shares the same pattern. - Dropdowns: Track which item is open (e.g.
openDropdownIndex). Usearia-expandedand a class on the submenu for visibility. On desktop, consider measuring and adjusting submenu position to avoid viewport overflow (see Astro Navbar script). - Keyboard: Handle
keydownon the menu: Arrow keys to move focus, Enter/Space to activate, Escape to close menu or dropdown. Userole="menu"androle="menuitem"(ormenuitemon links) for ARIA. - Click outside: Close menu/dropdown when focus or click is outside the navbar (e.g.
documentclick listener, or focus-within).
Full Astro Navbar documentation — structure, dropdown layout, and the inline script you can port to Svelte for toggle, dropdown positioning, and keyboard handling.