Skip to content

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.

minimal/section/navbar-announcement
Open ↗

Source

"use client";

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

export interface NavbarAnnouncementProps {
  brand?: string;
  brandHref?: string;
  announcement?: { label: string; cta: string; href: string } | null;
  links?: { label: string; href: string }[];
  /** Called when the search trigger is pressed (or ⌘K / Ctrl+K). */
  onSearch?: () => void;
  signIn?: { label: string; href: string };
  cta?: { label: string; href: string };
  className?: string;
}

/** Two-tier header: dismissible announcement bar above a navbar with a ⌘K search trigger. */
export function NavbarAnnouncement({
  brand = "Tracewise",
  brandHref = "/",
  announcement = { label: "Tracewise raises $40M Series B to end alert fatigue", cta: "Read the post", href: "#blog" },
  links = [
    { label: "Product", href: "#product" },
    { label: "Solutions", href: "#solutions" },
    { label: "Pricing", href: "#pricing" },
    { label: "Docs", href: "#docs" },
  ],
  onSearch,
  signIn = { label: "Log in", href: "#login" },
  cta = { label: "Get a demo", href: "#demo" },
  className,
}: NavbarAnnouncementProps) {
  const [dismissed, setDismissed] = useState(false);
  const [open, setOpen] = useState(false);
  const menuId = useId();

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k" && onSearch) {
        e.preventDefault();
        onSearch();
      }
      if (e.key === "Escape") setOpen(false);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onSearch]);

  return (
    <header className={cn("relative z-40 text-da-fg", className)}>
      {announcement && !dismissed && (
        <div className="relative bg-da-fg text-da-bg">
          <div className="da-container flex h-10 items-center justify-center gap-3 pr-10 text-[13px]">
            <p className="truncate">{announcement.label}</p>
            <a
              href={announcement.href}
              className="da-focus group hidden shrink-0 items-center gap-1 rounded-da-sm font-medium underline-offset-4 hover:underline sm:inline-flex"
            >
              {announcement.cta}
              <ArrowRight aria-hidden className="da-transition size-3.5 group-hover:translate-x-0.5" />
            </a>
          </div>
          <button
            type="button"
            onClick={() => setDismissed(true)}
            aria-label="Dismiss announcement"
            className="da-focus absolute top-1/2 right-3 grid size-6 -translate-y-1/2 place-items-center rounded-da-sm opacity-70 hover:opacity-100"
          >
            <X aria-hidden className="size-3.5" />
          </button>
        </div>
      )}
      <div className="border-b border-da-border bg-da-bg">
        <nav aria-label="Main" className="da-container flex h-14 items-center gap-6">
          <a href={brandHref} className="da-focus flex items-center gap-2 rounded-da-sm text-[15px] font-semibold tracking-tight">
            <svg aria-hidden viewBox="0 0 24 24" className="size-5 text-da-primary" fill="none">
              <path d="M3 12h4l2.5-6 5 12 2.5-6H21" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            {brand}
          </a>
          <ul className="hidden items-center gap-1 lg:flex">
            {links.map((l) => (
              <li key={l.href}>
                <a href={l.href} className="da-focus da-transition rounded-da-md px-3 py-1.5 text-sm text-da-muted-fg hover:text-da-fg">
                  {l.label}
                </a>
              </li>
            ))}
          </ul>
          <button
            type="button"
            onClick={onSearch}
            className="da-focus da-transition da-stroke ml-auto hidden h-8 w-56 items-center gap-2 rounded-da-md bg-da-surface px-2.5 text-[13px] text-da-muted-fg hover:border-da-border-strong sm:flex"
          >
            <Search aria-hidden className="size-3.5" />
            Search docs…
            <kbd className="ml-auto rounded-da-sm bg-da-muted px-1.5 font-da-mono text-[11px]">⌘K</kbd>
          </button>
          <div className="hidden items-center gap-2 lg:flex">
            <a href={signIn.href} className="da-focus da-transition rounded-da-md px-3 py-1.5 text-sm text-da-muted-fg hover:text-da-fg">
              {signIn.label}
            </a>
            <a
              href={cta.href}
              className="da-focus da-transition inline-flex h-8 items-center rounded-da-md bg-da-fg px-3.5 text-sm font-medium text-da-bg hover:bg-da-fg/85"
            >
              {cta.label}
            </a>
          </div>
          <button
            type="button"
            aria-expanded={open}
            aria-controls={menuId}
            aria-label={open ? "Close menu" : "Open menu"}
            onClick={() => setOpen((o) => !o)}
            className="da-focus ml-auto grid size-9 place-items-center rounded-da-md text-da-muted-fg hover:bg-da-muted sm:ml-0 lg:hidden"
          >
            {open ? <X aria-hidden className="size-5" /> : <Menu aria-hidden className="size-5" />}
          </button>
        </nav>
        <div id={menuId} hidden={!open} className="border-t border-da-border lg:hidden">
          <ul className="da-container py-2">
            {links.map((l) => (
              <li key={l.href}>
                <a href={l.href} onClick={() => setOpen(false)} className="da-focus block rounded-da-md px-3 py-2.5 text-[15px] hover:bg-da-muted">
                  {l.label}
                </a>
              </li>
            ))}
          </ul>
          <div className="da-container grid grid-cols-2 gap-2 border-t border-da-border py-3">
            <a href={signIn.href} className="da-focus da-stroke rounded-da-md py-2 text-center text-sm font-medium">
              {signIn.label}
            </a>
            <a href={cta.href} className="da-focus rounded-da-md bg-da-fg py-2 text-center text-sm font-medium text-da-bg">
              {cta.label}
            </a>
          </div>
        </div>
      </div>
    </header>
  );
}

export default NavbarAnnouncement;

modules/minimal/section/navbar-announcement/index.tsx

Props

PropTypeDefaultDescription
announcement{ label, cta, href } | null—Top bar (null hides it).
links{ label, href }[]—Nav links.
onSearch() => void—Called by the search button and ⌘K / Ctrl+K.
signIn / cta{ label, href }—Actions.
brand / brandHref / classNamestring—Brand and classes.

Other navbar variants in Minimal

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 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 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 CorporateNavbar

Navbar Mega

Navbar with a wide “Platform” mega menu: three titled columns of icon links plus a navy promo card, closing on Escape/outside click; stacked on mobile.

Neo CorporateNavbar

Navbar Scroll

Sticky navbar that starts tall and transparent and condenses on scroll into a white bordered bar with a subtle shadow and a smaller CTA.

Neo CorporateNavbar

Navbar Utility

Two-tier enterprise header: a slim surface-2 utility bar (system status, sales phone, language select, support/login) above the main navbar.

Neo CorporateNavbar

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