astro-better-nav-bar
A configurable top navigation bar for Astro sites. Supports dropdowns, a dark/light theme selector, a search button, login link, and CTA button. Designed for both docs and content sites.
Installation
$ npm install astro-better-nav-bar
Import the CSS in your global stylesheet:
@import "astro-better-nav-bar/style.css";
Basic usage
---
import { NavBar } from 'astro-better-nav-bar';
---
<NavBar
sectionTitle="My Site"
sectionTitleHref="/"
showThemeSelector
showSearch
loginHref="https://example.com/login"
ctaHref="/contact"
ctaLabel="Get started"
>
<img slot="logo" src="/logo.svg" alt="My Site" class="h-8 w-8" />
</NavBar>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
logoHref | string | / | URL the logo links to |
logoAriaLabel | string | Home | aria-label for logo link |
sectionTitle | string | — | Section label displayed next to logo |
sectionTitleHref | string | — | URL the section title links to |
dropdowns | Dropdown[] | [] | Dropdown menus (see below) |
showThemeSelector | boolean | false | Show the light/dark theme toggle |
showSearch | boolean | false | Show a search button (opens native browser search) |
loginHref | string | — | URL for the “Log in” link |
loginLabel | string | Log in | Text for the login link |
ctaHref | string | — | URL for the CTA button |
ctaLabel | string | — | Text for the CTA button |
breadcrumbs | {title, href}[] | [] | Breadcrumb trail displayed below the main bar |
Slots
| Slot | Description |
|---|---|
logo | Logo element (image, SVG, or Astro component) |
sidebar-toggle | Renders at the left of the mobile bar; use for a docs sidebar hamburger |
extra-actions | Additional items in the desktop and mobile action area |
Sidebar toggle
The sidebar-toggle slot is designed for a CSS-only docs sidebar hamburger.
Place a <label> that controls a hidden checkbox; CSS :has() then shows and hides the sidebar without any JavaScript.
<!-- hidden checkbox drives sidebar state -->
<input type="checkbox" id="nav-sidebar-open" class="nav-sidebar-checkbox" aria-hidden="true">
<NavBar ...>
<label slot="sidebar-toggle" for="nav-sidebar-open" class="nav-sidebar-toggle" aria-label="Open navigation">
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
<path d="M1 2.75A.75.75 0 011.75 2h12.5a.75.75 0 010 1.5H1.75A.75.75 0 011 2.75zm0 5A.75.75 0 011.75 7h12.5a.75.75 0 010 1.5H1.75A.75.75 0 011 7.75zm0 5a.75.75 0 01.75-.75h12.5a.75.75 0 010 1.5H1.75a.75.75 0 01-.75-.75z"/>
</svg>
</label>
</NavBar>
<!-- clicking backdrop unchecks the checkbox, closing the sidebar -->
<label class="sidebar-backdrop" for="nav-sidebar-open" aria-hidden="true"></label>
Then wire up the sidebar in CSS:
.nav-sidebar-checkbox { position: fixed; opacity: 0; pointer-events: none; width: 0; height: 0; }
.nav-sidebar-toggle {
display: flex;
align-items: center;
justify-content: center;
height: 1.75rem; width: 1.75rem;
border-radius: 0.25rem;
color: var(--nav-text, #fff);
cursor: pointer;
}
/* hide when the sidebar is already visible inline */
@media (min-width: 769px) { .nav-sidebar-toggle { display: none; } }
.sidebar-backdrop {
display: none;
position: fixed; inset: 0; z-index: 39;
background: rgba(0, 0, 0, 0.4); cursor: pointer;
}
@media (max-width: 768px) {
.doc-sidebar {
position: fixed; left: 0; top: 3.75rem; bottom: 0;
z-index: 40; transform: translateX(-100%);
transition: transform 0.2s ease;
}
body:has(.nav-sidebar-checkbox:checked) .doc-sidebar { transform: translateX(0); }
body:has(.nav-sidebar-checkbox:checked) .sidebar-backdrop { display: block; }
}
Dropdowns
Each dropdown takes a label (the button text) and an items array:
type DropdownItem = { name: string; href: string };
type Dropdown = { label: string; items: DropdownItem[] };
<NavBar
dropdowns={[
{
label: 'Resources',
items: [
{ name: 'Docs', href: '/docs' },
{ name: 'Blog', href: '/blog' },
{ name: 'API', href: '/api' },
],
},
]}
...
/>
Theme selector
When showThemeSelector is true, a theme toggle appears in the nav. It reads and writes
localStorage.getItem('theme') and toggles the .dark class on document.documentElement.
The desktop nav shows a moon-icon dropdown with three options: Light, Dark, and System. Mobile shows a single toggle button.
CSS customization
Override these CSS custom properties in your stylesheet:
:root {
--nav-bg: #5E2750; /* nav bar background */
--nav-border: #4a1f40; /* nav bottom border */
--nav-text: #f5e6f0; /* nav text color */
--nav-text-muted: #d4a8c8; /* muted text (e.g. section title) */
--nav-hover: rgba(255,255,255,0.12); /* hover background */
--nav-cta-bg: #D24D15; /* CTA button background */
--nav-cta-hover-bg: #b83d0e; /* CTA button hover */
--nav-max-width: 1400px; /* max content width */
}
The nav bar always uses --nav-* variables regardless of dark mode, since the nav typically
has its own distinct background color that does not follow the page’s light/dark toggle.