react ~5 KB 0 deps v0.1.0 ↗ GitHub ↗

@mshafiqyajid/react-navbar

Headless navbar hook and styled component for React. Sticky positioning, transparent-on-top with scroll detection, collapsible mobile menu with hamburger toggle, four variants, three sizes, full keyboard navigation, and ARIA-compliant.

Playground #

Props
TSX
import { NavbarStyled } from "@mshafiqyajid/react-navbar/styled";
import "@mshafiqyajid/react-navbar/styles.css";

<NavbarStyled
  brand={brand}
  items={navItems}
  actions={actions}
/>

Install #

npm install @mshafiqyajid/react-navbar

Quick start #

import { NavbarStyled } from "@mshafiqyajid/react-navbar/styled";
import "@mshafiqyajid/react-navbar/styles.css";

const navItems = [
  { label: "Home", href: "/", active: true },
  { label: "Docs", href: "/docs" },
  { label: "Pricing", href: "/pricing" },
];

<NavbarStyled
  brand={<strong>Acme</strong>}
  items={navItems}
  actions={<button>Sign in</button>}
/>

Sticky + transparent on top #

Set sticky to keep the navbar fixed at the top of the viewport. Pair with transparentOnTop to start transparent and transition to a solid background once the user scrolls past the threshold.

<NavbarStyled
  brand={<strong>Acme</strong>}
  items={navItems}
  sticky
  transparentOnTop
  scrollThreshold={16}
/>

Variants #

<NavbarStyled items={navItems} variant="default" />    {/* subtle bottom border */}
<NavbarStyled items={navItems} variant="bordered" />   {/* border + shadow */}
<NavbarStyled items={navItems} variant="filled" />     {/* dark filled background */}
<NavbarStyled items={navItems} variant="transparent" />{/* fully transparent */}

Sizes #

<NavbarStyled items={navItems} size="sm" />  {/* 48px height */}
<NavbarStyled items={navItems} size="md" />  {/* 56px — default */}
<NavbarStyled items={navItems} size="lg" />  {/* 64px height */}
const navItems = [
  { label: "Home",  href: "/",      active: true, icon: <HomeIcon /> },
  { label: "Docs",  href: "/docs",               icon: <BookIcon /> },
  { label: "Admin", href: "/admin", disabled: true },
];

<NavbarStyled brand={<strong>Acme</strong>} items={navItems} />

Mobile menu toggle #

A hamburger button appears automatically below the mobileBreakpoint (default 768 px). Clicking it toggles a slide-down menu. Pressing Escape closes it.

<NavbarStyled
  brand={<strong>Acme</strong>}
  items={navItems}
  actions={<button>Sign in</button>}
  mobileBreakpoint={768}
  onMenuToggle={(open) => console.log("menu:", open)}
/>

Headless hook #

import { useNavbar } from "@mshafiqyajid/react-navbar";

function MyNavbar() {
  const {
    navProps,
    menuProps,
    toggleProps,
    isMenuOpen,
    isScrolled,
  } = useNavbar({
    scrollThreshold: 16,
    onMenuToggle: (open) => console.log("menu:", open),
  });

  return (
    <nav {...navProps} style={{ background: isScrolled ? "#fff" : "transparent" }}>
      <div style={{ display: "flex", alignItems: "center", padding: "0 1rem" }}>
        <strong>Acme</strong>
        <button {...toggleProps} aria-label="Toggle menu">☰</button>
      </div>
      <div {...menuProps} hidden={!isMenuOpen}>
        <a href="/docs">Docs</a>
        <a href="/pricing">Pricing</a>
      </div>
    </nav>
  );
}

API — NavbarStyled #

PropTypeDefaultDescription
brandReactNodeBrand logo or wordmark rendered on the left
itemsNavbarItem[]Navigation links (see NavbarItem below)
actionsReactNodeRight-side content (buttons, avatar, etc.)
variant"default" | "bordered" | "filled" | "transparent""default"Visual style
size"sm" | "md" | "lg""md"Navbar height (48 / 56 / 64 px)
stickybooleanfalseStick to the top of the viewport while scrolling
transparentOnTopbooleanfalseUse transparent background when page is at the top
scrollThresholdnumber16Pixels scrolled before isScrolled becomes true
mobileBreakpointnumber768Viewport width in px below which the mobile menu appears
onMenuToggle(open: boolean) => voidCalled when the mobile menu opens or closes
childrenReactNodeExtra content appended inside the nav bar row
classNamestringExtra class on the root <nav>
styleCSSPropertiesInline style on the root <nav>
refRef<HTMLElement>Forwarded to the <nav> element

API — NavbarItem #

KeyTypeDescription
labelstringLink text (required)
hrefstringLink target (required)
activebooleanMark as current page (aria-current="page")
disabledbooleanPrevent interaction (aria-disabled="true")
iconReactNodeOptional icon rendered before the label

API — useNavbar #

KeyTypeDescription
navPropsobjectSpread on <nav>: role="navigation", aria-label
menuPropsobjectSpread on the mobile menu container: id="rnav-menu"
togglePropsobjectSpread on the hamburger button: aria-expanded, aria-controls, onClick
isMenuOpenbooleanWhether the mobile menu is currently open
isScrolledbooleanWhether the page has scrolled past the threshold

Data attributes #

AttributeValuesDescription
data-variant"default" | "bordered" | "filled" | "transparent"Current variant (or "transparent" when transparentOnTop + at top)
data-size"sm" | "md" | "lg"Current size
data-stickypresent / absentPresent when sticky is true
data-scrolledpresent / absentPresent when page is scrolled past threshold
data-menu-openpresent / absentPresent when mobile menu is open

Keyboard support #

KeyBehaviour
TabStandard focus order through all interactive elements
EscapeCloses the mobile menu when it is open
Edit this page on GitHub