{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "navbar",
  "title": "Navbar",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A responsive site header that gains a border and shadow on scroll, can hide while scrolling down, and turns its links into a sheet menu on small screens.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/sheet.json",
    "https://ui.ballmac.com/r/scroll.json",
    "https://ui.ballmac.com/r/i18n.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/navbar.tsx",
      "content": "// Ballmac UI: Navbar. https://ui.ballmac.com/components/navbar\n\"use client\";\n\nimport * as React from \"react\";\nimport { Menu } from \"lucide-react\";\nimport { Sheet, SheetContent, SheetDescription, SheetTitle, SheetTrigger } from \"@/components/ballmac/sheet\";\nimport { useScrollDirection, useScrolled, type ScrollContainer } from \"@/lib/ballmac/scroll\";\nimport { cn } from \"@/lib/utils\";\nimport { useMessages } from \"@/lib/ballmac/i18n\";\n\ntype NavbarContextValue = { closeMobile: () => void; scrolled: boolean };\nconst NavbarContext = React.createContext<NavbarContextValue>({ closeMobile: () => {}, scrolled: false });\n\ntype NavbarProps = React.ComponentProps<\"header\"> & {\n  /** Stick to the top of the page. */\n  sticky?: boolean;\n  /** Slide out of view while scrolling down and back in while scrolling up. Stays visible while it holds focus. */\n  hideOnScroll?: boolean;\n  /** When to draw the bottom border: `scrolled` only after the page moves, `always`, or `never`. */\n  border?: \"scrolled\" | \"always\" | \"never\";\n  /** Max width of the content row. */\n  containerClassName?: string;\n  /** A scrollable element to watch instead of the page (for a header inside a panel or preview). */\n  scrollContainer?: ScrollContainer;\n};\n\n/** A responsive site header. Compose NavbarBrand, NavbarLinks, NavbarActions and NavbarMobileMenu. */\nfunction Navbar({\n  sticky = true,\n  hideOnScroll = false,\n  border = \"scrolled\",\n  className,\n  containerClassName,\n  scrollContainer,\n  children,\n  ...props\n}: NavbarProps) {\n  const scrolled = useScrolled(8, scrollContainer);\n  const direction = useScrollDirection(12, scrollContainer);\n  const hidden = hideOnScroll && scrolled && direction === \"down\";\n  const value = React.useMemo(() => ({ closeMobile: () => {}, scrolled }), [scrolled]);\n  return (\n    <NavbarContext.Provider value={value}>\n      <header\n        data-slot=\"navbar\"\n        data-scrolled={scrolled || undefined}\n        data-hidden={hidden || undefined}\n        className={cn(\n          \"z-40 w-full border-b border-transparent bg-background/80 backdrop-blur-md transition-[transform,border-color,box-shadow] duration-300 motion-reduce:transition-none supports-[backdrop-filter]:bg-background/70\",\n          sticky && \"sticky top-0\",\n          border === \"always\" && \"border-border\",\n          border === \"scrolled\" && \"data-[scrolled]:border-border data-[scrolled]:shadow-[0_1px_0_0_rgb(0_0_0/0.02),0_8px_24px_-16px_rgb(0_0_0/0.18)]\",\n          hidden && \"-translate-y-full focus-within:translate-y-0\",\n          className,\n        )}\n        {...props}\n      >\n        <div className={cn(\"mx-auto flex h-14 w-full max-w-6xl items-center gap-4 px-4 sm:px-6\", containerClassName)}>\n          {children}\n        </div>\n      </header>\n    </NavbarContext.Provider>\n  );\n}\n\ntype NavbarBrandProps = React.ComponentProps<\"a\">;\nfunction NavbarBrand({ className, ...props }: NavbarBrandProps) {\n  return (\n    <a\n      data-slot=\"navbar-brand\"\n      className={cn(\n        \"-ms-1 flex shrink-0 items-center gap-2 rounded-md px-1 text-[15px] font-semibold tracking-tight outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\ntype NavbarLinksProps = React.ComponentProps<\"nav\"> & {\n  /** Accessible name of the navigation landmark. */\n  label?: string;\n};\n/** The primary links. Hidden below the `md` breakpoint; put the same links in NavbarMobileMenu. */\nfunction NavbarLinks({ className, label, children, ...props }: NavbarLinksProps) {\n  const msg = useMessages()\n  label ??= msg(\"navbar.label\", \"Main\")\n  return (\n    <nav aria-label={label} data-slot=\"navbar-links\" className={cn(\"hidden md:block\", className)} {...props}>\n      <ul className=\"flex items-center gap-1\">{children}</ul>\n    </nav>\n  );\n}\n\ntype NavbarLinkProps = React.ComponentProps<\"a\"> & {\n  /** Marks the link as the current page (`aria-current=\"page\"`). */\n  active?: boolean;\n};\nfunction NavbarLink({ active = false, className, children, ...props }: NavbarLinkProps) {\n  return (\n    <li>\n      <a\n        data-slot=\"navbar-link\"\n        data-active={active || undefined}\n        aria-current={active ? \"page\" : undefined}\n        className={cn(\n          \"relative inline-flex h-9 items-center rounded-md px-3 text-sm font-medium text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[active]:text-foreground\",\n          \"after:absolute after:inset-x-3 after:-bottom-[9px] after:h-0.5 after:scale-x-0 after:rounded-full after:bg-primary after:transition-transform after:duration-200 data-[active]:after:scale-x-100 motion-reduce:after:transition-none\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </a>\n    </li>\n  );\n}\n\ntype NavbarActionsProps = React.ComponentProps<\"div\">;\n/** Buttons on the right: sign in, theme toggle, call to action. */\nfunction NavbarActions({ className, ...props }: NavbarActionsProps) {\n  return <div data-slot=\"navbar-actions\" className={cn(\"ms-auto flex items-center gap-2\", className)} {...props} />;\n}\n\ntype NavbarMobileMenuProps = Omit<React.ComponentProps<typeof SheetContent>, \"side\"> & {\n  /** Accessible name of the menu button and the panel. */\n  label?: string;\n};\n/** A menu button (shown below `md`) that opens the links in a sheet. Links inside close it when chosen. */\nfunction NavbarMobileMenu({ label, className, children, ...props }: NavbarMobileMenuProps) {\n  const msg = useMessages()\n  label ??= msg(\"navbar.label2\", \"Menu\")\n  const [open, setOpen] = React.useState(false);\n  const parent = React.useContext(NavbarContext);\n  const value = React.useMemo(() => ({ ...parent, closeMobile: () => setOpen(false) }), [parent]);\n  return (\n    <Sheet open={open} onOpenChange={setOpen}>\n      <SheetTrigger\n        data-slot=\"navbar-mobile-trigger\"\n        aria-label={label}\n        className=\"ms-auto inline-flex size-9 items-center justify-center rounded-md outline-none transition-colors hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/50 md:hidden\"\n      >\n        <Menu aria-hidden=\"true\" className=\"size-5\" />\n      </SheetTrigger>\n      <SheetContent side=\"end\" className={cn(\"w-72 sm:w-80\", className)} {...props}>\n        <SheetTitle className=\"px-5 pt-5 text-base font-semibold\">{label}</SheetTitle>\n        <SheetDescription className=\"sr-only\">{msg(\"navbar.siteNavigation\", \"Site navigation\")}</SheetDescription>\n        <NavbarContext.Provider value={value}>\n          <nav aria-label={label} className=\"flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto px-3 pb-5\">\n            {children}\n          </nav>\n        </NavbarContext.Provider>\n      </SheetContent>\n    </Sheet>\n  );\n}\n\ntype NavbarMobileLinkProps = React.ComponentProps<\"a\"> & { active?: boolean };\n/** A full-width link for NavbarMobileMenu that closes the menu on click. */\nfunction NavbarMobileLink({ active = false, className, onClick, ...props }: NavbarMobileLinkProps) {\n  const { closeMobile } = React.useContext(NavbarContext);\n  return (\n    <a\n      data-slot=\"navbar-mobile-link\"\n      data-active={active || undefined}\n      aria-current={active ? \"page\" : undefined}\n      onClick={(event) => {\n        onClick?.(event);\n        closeMobile();\n      }}\n      className={cn(\n        \"flex h-11 items-center rounded-lg px-3 text-[15px] font-medium outline-none transition-colors hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/50 data-[active]:bg-accent data-[active]:text-accent-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Navbar,\n  NavbarBrand,\n  NavbarLinks,\n  NavbarLink,\n  NavbarActions,\n  NavbarMobileMenu,\n  NavbarMobileLink,\n  type NavbarProps,\n  type NavbarBrandProps,\n  type NavbarLinksProps,\n  type NavbarLinkProps,\n  type NavbarActionsProps,\n  type NavbarMobileMenuProps,\n  type NavbarMobileLinkProps,\n};\n",
      "type": "registry:ui",
      "target": "@components/ballmac/navbar.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "header",
      "navigation",
      "sticky",
      "responsive"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "Compose Navbar with NavbarBrand, NavbarLinks/NavbarLink (active sets aria-current), NavbarActions and NavbarMobileMenu with NavbarMobileLink.",
      "whenToUse": [
        "Marketing and docs site headers",
        "Headers that should get out of the way on long pages"
      ],
      "whenNotToUse": [
        "Application chrome with a sidebar; use app-shell",
        "Wide dropdown panels; add mega-menu"
      ],
      "composesWith": [
        "mega-menu",
        "button",
        "sheet"
      ],
      "a11y": [
        {
          "keys": "Tab",
          "action": "Moves through brand, links, actions and the menu button"
        },
        {
          "keys": "Enter / Space",
          "action": "Opens the mobile menu; Escape closes it and returns focus"
        },
        {
          "keys": "Screen readers",
          "action": "Links are in a labelled navigation landmark; the current page has aria-current"
        }
      ],
      "customization": [
        "sticky and hideOnScroll",
        "border: scrolled | always | never",
        "scrollContainer for headers inside panels",
        "mobile menu label"
      ]
    },
    "examples": [
      "navbar-demo",
      "navbar-states"
    ],
    "url": "https://ui.ballmac.com/components/navbar"
  },
  "categories": [
    "navigation"
  ],
  "type": "registry:ui"
}