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.

Current version: 0.1.1 --npm

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

PropTypeDefaultDescription
logoHrefstring/URL the logo links to
logoAriaLabelstringHomearia-label for logo link
sectionTitlestringSection label displayed next to logo
sectionTitleHrefstringURL the section title links to
dropdownsDropdown[][]Dropdown menus (see below)
showThemeSelectorbooleanfalseShow the light/dark theme toggle
showSearchbooleanfalseShow a search button (opens native browser search)
loginHrefstringURL for the “Log in” link
loginLabelstringLog inText for the login link
ctaHrefstringURL for the CTA button
ctaLabelstringText for the CTA button
breadcrumbs{title, href}[][]Breadcrumb trail displayed below the main bar

Slots

SlotDescription
logoLogo element (image, SVG, or Astro component)
sidebar-toggleRenders at the left of the mobile bar; use for a docs sidebar hamburger
extra-actionsAdditional items in the desktop and mobile action area

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; }
}

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 */
}
Dark mode

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.