Skip to content

Navbar Corporate

Corporate navbar: logo, two dropdown menus (items with descriptions), plain links, “Sign in”, bordered “Contact sales” and a blue primary; mobile accordion menu.

neo-corporate/section/navbar-corporate
Open ↗

Source

"use client";

import { useEffect, useId, useRef, useState } from "react";
import { ChevronDown, Menu, X } from "lucide-react";
import { cn } from "@/lib/utils";

export interface NavbarCorporateMenu {
  label: string;
  items: { label: string; description: string; href: string }[];
}

export interface NavbarCorporateProps {
  brand?: string;
  brandHref?: string;
  menus?: NavbarCorporateMenu[];
  links?: { label: string; href: string }[];
  signIn?: { label: string; href: string };
  sales?: { label: string; href: string };
  cta?: { label: string; href: string };
  className?: string;
}

const DEFAULT_MENUS: NavbarCorporateMenu[] = [
  {
    label: "Product",
    items: [
      { label: "Invoicing", description: "Branded invoices and automatic reminders.", href: "#invoicing" },
      { label: "Payments", description: "Card, ACH and SEPA in 40 currencies.", href: "#payments" },
      { label: "Spend management", description: "Cards, approvals and receipts.", href: "#spend" },
      { label: "Reconciliation", description: "Match bank lines to invoices automatically.", href: "#recon" },
    ],
  },
  {
    label: "Solutions",
    items: [
      { label: "Startups", description: "Get paid faster from day one.", href: "#startups" },
      { label: "Mid-market", description: "Multi-entity close in days.", href: "#midmarket" },
      { label: "Enterprise", description: "Controls, SSO and audit trails.", href: "#enterprise" },
    ],
  },
];

function LedgerlyMark({ className }: { className?: string }) {
  return (
    <svg aria-hidden viewBox="0 0 28 28" className={cn("size-7", className)}>
      <rect width="28" height="28" rx="7" fill="var(--da-primary)" />
      <path d="M8 8v12h12" stroke="var(--da-primary-fg)" strokeWidth="2.6" fill="none" strokeLinecap="round" />
      <path d="M13 15h7M13 11h7" stroke="var(--da-primary-fg)" strokeWidth="2.2" strokeLinecap="round" opacity=".7" />
    </svg>
  );
}

/** Corporate navbar: logo, two dropdown menus (items with descriptions), plain links, “Sign in”, bordered “Contact sales” and a blue primary; mobile accordion menu. */
export function NavbarCorporate({
  brand = "Ledgerly",
  brandHref = "/",
  menus = DEFAULT_MENUS,
  links = [
    { label: "Customers", href: "#customers" },
    { label: "Pricing", href: "#pricing" },
  ],
  signIn = { label: "Sign in", href: "#login" },
  sales = { label: "Contact sales", href: "#sales" },
  cta = { label: "Start free trial", href: "#signup" },
  className,
}: NavbarCorporateProps) {
  const [open, setOpen] = useState<string | null>(null);
  const [mobile, setMobile] = useState(false);
  const root = useRef<HTMLElement>(null);
  const mobileId = useId();

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") {
        setOpen(null);
        setMobile(false);
      }
    };
    const onDown = (e: MouseEvent) => root.current && !root.current.contains(e.target as Node) && setOpen(null);
    window.addEventListener("keydown", onKey);
    document.addEventListener("mousedown", onDown);
    return () => {
      window.removeEventListener("keydown", onKey);
      document.removeEventListener("mousedown", onDown);
    };
  }, []);

  return (
    <header ref={root} className={cn("relative z-40 border-b border-da-border bg-da-bg text-da-fg", className)}>
      <nav aria-label="Main" className="da-container flex h-16 items-center gap-8">
        <a href={brandHref} className="da-focus flex items-center gap-2.5 rounded-da-sm font-da-display text-lg font-extrabold tracking-da-display">
          <LedgerlyMark />
          {brand}
        </a>
        <ul className="hidden items-center gap-1 lg:flex">
          {menus.map((m) => (
            <li key={m.label} className="relative">
              <button
                type="button"
                aria-expanded={open === m.label}
                onClick={() => setOpen(open === m.label ? null : m.label)}
                className={cn(
                  "da-focus da-transition inline-flex items-center gap-1 rounded-da-sm px-3 py-2 text-[15px] font-medium hover:text-da-fg",
                  open === m.label ? "text-da-fg" : "text-da-muted-fg",
                )}
              >
                {m.label}
                <ChevronDown aria-hidden className={cn("da-transition size-4", open === m.label && "rotate-180")} />
              </button>
              {open === m.label && (
                <ul className="da-stroke absolute top-full left-0 mt-2 w-80 rounded-da-lg bg-da-surface p-2 text-da-surface-fg shadow-da-lg transition-[opacity,translate] duration-(--da-duration) ease-da starting:-translate-y-1 starting:opacity-0">
                  {m.items.map((it) => (
                    <li key={it.href}>
                      <a href={it.href} onClick={() => setOpen(null)} className="da-focus da-transition block rounded-da-md p-3 hover:bg-da-surface-2">
                        <span className="block text-sm font-semibold">{it.label}</span>
                        <span className="mt-0.5 block text-sm text-da-muted-fg">{it.description}</span>
                      </a>
                    </li>
                  ))}
                </ul>
              )}
            </li>
          ))}
          {links.map((l) => (
            <li key={l.href}>
              <a href={l.href} className="da-focus da-transition rounded-da-sm px-3 py-2 text-[15px] font-medium text-da-muted-fg hover:text-da-fg">
                {l.label}
              </a>
            </li>
          ))}
        </ul>
        <div className="ml-auto hidden items-center gap-2 lg:flex">
          <a href={signIn.href} className="da-focus da-transition rounded-da-sm px-3 py-2 text-[15px] font-medium text-da-muted-fg hover:text-da-fg">
            {signIn.label}
          </a>
          <a
            href={sales.href}
            className="da-focus da-transition da-stroke inline-flex h-10 items-center rounded-da-md bg-da-surface px-4 text-sm font-semibold hover:border-da-border-strong"
          >
            {sales.label}
          </a>
          <a
            href={cta.href}
            className="da-focus da-transition inline-flex h-10 items-center rounded-da-md bg-da-primary px-4 text-sm font-semibold text-da-primary-fg shadow-da-sm hover:bg-da-primary/90"
          >
            {cta.label}
          </a>
        </div>
        <button
          type="button"
          aria-expanded={mobile}
          aria-controls={mobileId}
          aria-label={mobile ? "Close menu" : "Open menu"}
          onClick={() => setMobile((v) => !v)}
          className="da-focus da-stroke ml-auto grid size-10 place-items-center rounded-da-md lg:hidden"
        >
          {mobile ? <X aria-hidden className="size-5" /> : <Menu aria-hidden className="size-5" />}
        </button>
      </nav>
      <div id={mobileId} hidden={!mobile} className="border-t border-da-border lg:hidden">
        <div className="da-container py-3">
          {menus.map((m) => (
            <details key={m.label} className="group border-b border-da-border">
              <summary className="da-focus flex cursor-pointer list-none items-center justify-between py-3 font-semibold [&::-webkit-details-marker]:hidden">
                {m.label}
                <ChevronDown aria-hidden className="da-transition size-4 group-open:rotate-180" />
              </summary>
              <ul className="pb-3">
                {m.items.map((it) => (
                  <li key={it.href}>
                    <a href={it.href} className="da-focus block rounded-da-sm py-2 text-da-muted-fg hover:text-da-fg">
                      {it.label}
                    </a>
                  </li>
                ))}
              </ul>
            </details>
          ))}
          {links.map((l) => (
            <a key={l.href} href={l.href} className="da-focus block border-b border-da-border py-3 font-semibold">
              {l.label}
            </a>
          ))}
          <div className="mt-4 grid gap-2 sm:grid-cols-2">
            <a href={sales.href} className="da-focus da-stroke rounded-da-md py-2.5 text-center text-sm font-semibold">
              {sales.label}
            </a>
            <a href={cta.href} className="da-focus rounded-da-md bg-da-primary py-2.5 text-center text-sm font-semibold text-da-primary-fg">
              {cta.label}
            </a>
          </div>
        </div>
      </div>
    </header>
  );
}

export default NavbarCorporate;

modules/neo-corporate/section/navbar-corporate/index.tsx

Props

PropTypeDefaultDescription
brandstring—Brand name.
brandHrefstring—Brand link target.
menusNavbarCorporateMenu[]—Menus.
links{ label: string; href: string }[]—Links.
signIn{ label: string; href: string }—Sign In.
sales{ label: string; href: string }—Sales.
cta{ label: string; href: string }—Cta.
classNamestring—Extra classes on the root.

Other navbar variants in Neo Corporate

Navbar in other art directions

Navbar Bold

Sticky top bar with square logo mark, mono uppercase links, underlined login and a pressable yellow CTA. Collapses into a full-width stacked menu on mobile.

BrutalistNavbar

Navbar Centered

Boxed navbar card with a hard shadow: links split left and right around a tilted yellow wordmark sticker in the center, ink CTA pressing into its shadow. Mobile opens a two-column ruled menu grid.

BrutalistNavbar

Navbar Overlay

Minimal bar (wordmark + ink MENU button with animated burger) that opens a full-screen yellow overlay with giant numbered links sliding on hover, a contact line and CTA. Same menu on every screen size.

BrutalistNavbar

Navbar Ticker

Two-tier sticky header: a scrolling ink announcement ticker on top, then a ruled bar where every link is a full-height cell that floods yellow on hover and a blue CTA block on the right.

BrutalistNavbar

Navbar Bar

Full-width sticky frosted bar with a Features dropdown that opens a glass panel of four icon cards, plain links and a gradient pill CTA; stacked mobile menu.

GlassNavbar

Navbar Dock

macOS-style floating bottom dock: a glass pill of round icon links that magnify with a spring when hovered (neighbours too), tooltips, a gradient active item with dot and an ink CTA.

GlassNavbar

Navbar Floating

Floating frosted pill navbar detached from the top edge: gradient orb logo, centered links, gradient CTA. On mobile the pill opens a frosted dropdown panel that fades in.

GlassNavbar

Navbar Islands

Three separate floating glass islands — brand pill, centered links pill, actions pill with gradient CTA — that merge into a single button and frosted panel on mobile.

GlassNavbar

Navbar Announcement

Two-tier header: a dismissible ink announcement bar with a link, above a hairline navbar with links, a ⌘K search trigger (wired to onSearch) and log in / demo actions.

MinimalNavbar

Navbar Blur

Sticky 56px top bar that is transparent at the top of the page and turns into a translucent blurred bar with a hairline once scrolled. Muted links, ink CTA, compact mobile menu.

MinimalNavbar

Navbar Mega

Navbar with a full-width Product mega menu: six icon + description items in a 3-column grid and a featured launch card, closes on outside click and Escape; grouped mobile menu.

MinimalNavbar

Navbar Pill

Floating, centered pill navbar with backdrop blur: logo, links with a shared hover/active pill indicator, ink CTA; collapses into a dropdown sheet with Escape support on mobile.

MinimalNavbar

Navbar Fullscreen

Minimal bar (logo + “Menu”) that opens a full-screen ink overlay with giant stacked links sliding up line by line, mono notes and contact details; Escape closes and scroll is locked.

Mono CleanNavbar

Navbar Index

Studio-style index navbar: numbered links “(01) Work”, a live local clock with city in mono, availability dot in the signal color and an underlined text CTA; stacked list on mobile.

Mono CleanNavbar

Navbar Meta

Two-tier editorial header: a mono meta strip (version, status with signal dot, changelog link) over a nav bar closed by a full-ink rule; oversize logo wordmark on desktop; stacked menu on mobile.

Mono CleanNavbar

Navbar Mono

Clean monochrome navbar on a hairline: square logo, links whose underline wipes in on hover (orange dot marks the active one), text sign-in and an ink button; text “Menu/Close” toggle opens a ruled list on mobile.

Mono CleanNavbar

Navbar Announce

Sage announcement strip (leaf icon, message, link, dismiss) above a simple cream navbar with a terracotta-tinted secondary pill and sage primary pill; drop-down menu on mobile.

Organic SoftNavbar

Navbar Floating

Floating pill navbar: a rounded, softly blurred surface bar detached from the top edge, with centered links and an arrow CTA; expands into a rounded panel on mobile.

Organic SoftNavbar

Navbar Organic

Calm cream navbar: round leaf logo + serif wordmark, links with a hand-drawn underline on the active one, text sign-in and a sage pill CTA; rounded sheet menu on mobile.

Organic SoftNavbar

Navbar Split

Editorial symmetric navbar: links split on both sides of a centered logo + large serif wordmark, a thin warm rule below, outlined pill CTA; full-width stacked menu on mobile.

Organic SoftNavbar

Navbar Centered

Symmetric navbar inside a soft rounded well: links split left and right of a centered wordmark with two overlapping dots, ink pill CTA at the far right; stacked sheet on mobile.

Soft FlatNavbar

Navbar Sheet

Minimal bar with a wordmark and a big “Menu” pill that unfolds a grid of pastel link tiles (title, description, arrow) with a staggered bouncy entrance, on every screen size.

Soft FlatNavbar

Navbar Soft

Friendly sticky navbar: rounded pastel logo mark, pill links with a soft lavender active fill, text log-in and a periwinkle pill CTA; rounded drop-down sheet on mobile.

Soft FlatNavbar

Navbar Tabs

Two-row header: brand and CTA on top, then a horizontally scrollable strip of pill tabs with emoji where the active tab is an ink-filled pill.

Soft FlatNavbar