{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "header-1",
  "title": "Header 1: sticky with mobile menu",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "Sticky site header with brand, main links, sign-in and primary action, and an accessible mobile menu that closes on Escape or link tap.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/button.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blocks/header-1/header-1.tsx",
      "content": "// Ballmac UI: Header 1. https://ui.ballmac.com/blocks/header-1\n\"use client\"\n\nimport * as React from \"react\"\nimport { Menu, X } from \"lucide-react\"\n\nimport { Button, buttonVariants } from \"@/components/ballmac/button\"\nimport { cn } from \"@/lib/utils\"\n\ntype NavLink = { label: string; href: string }\n\ntype Header1Props = React.ComponentProps<\"header\"> & {\n  /** Brand name or logo. */\n  brand?: React.ReactNode\n  /** Where the brand links to. */\n  brandHref?: string\n  /** Main navigation links. */\n  links?: NavLink[]\n  /** Quiet action on the right, e.g. sign in. */\n  secondaryAction?: NavLink\n  /** Main action on the right. */\n  primaryAction?: NavLink\n  /** Stick to the top with a blurred background. */\n  sticky?: boolean\n}\n\nfunction Header1({\n  brand = \"Acme\",\n  brandHref = \"#\",\n  links = [\n    { label: \"Product\", href: \"#\" },\n    { label: \"Pricing\", href: \"#\" },\n    { label: \"Customers\", href: \"#\" },\n    { label: \"Docs\", href: \"#\" },\n  ],\n  secondaryAction = { label: \"Sign in\", href: \"#\" },\n  primaryAction = { label: \"Get started\", href: \"#\" },\n  sticky = true,\n  className,\n  ...props\n}: Header1Props) {\n  const [open, setOpen] = React.useState(false)\n  const menuId = React.useId()\n  React.useEffect(() => {\n    if (!open) return\n    const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setOpen(false)\n    document.addEventListener(\"keydown\", onKey)\n    return () => document.removeEventListener(\"keydown\", onKey)\n  }, [open])\n  return (\n    <header data-slot=\"header-1\" className={cn(\"z-40 w-full border-b bg-background/80 backdrop-blur-xl\", sticky && \"sticky top-0\", className)} {...props}>\n      <div className=\"mx-auto flex h-16 max-w-6xl items-center gap-8 px-4 sm:px-6\">\n        <a href={brandHref} className=\"rounded-md text-lg font-semibold tracking-tight outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\">\n          {brand}\n        </a>\n        <nav aria-label=\"Main\" className=\"hidden md:block\">\n          <ul className=\"flex items-center gap-1\">\n            {links.map((l) => (\n              <li key={l.label}>\n                <a href={l.href} className=\"rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors outline-none hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50\">\n                  {l.label}\n                </a>\n              </li>\n            ))}\n          </ul>\n        </nav>\n        <div className=\"ms-auto hidden items-center gap-2 md:flex\">\n          <a className={buttonVariants({ variant: \"ghost\" })} href={secondaryAction.href}>{secondaryAction.label}</a>\n          <a className={buttonVariants({ shape: \"pill\" })} href={primaryAction.href}>{primaryAction.label}</a>\n        </div>\n        <Button\n          variant=\"ghost\"\n          size=\"icon\"\n          className=\"ms-auto md:hidden\"\n          aria-expanded={open}\n          aria-controls={menuId}\n          aria-label={open ? \"Close menu\" : \"Open menu\"}\n          onClick={() => setOpen((o) => !o)}\n        >\n          {open ? <X /> : <Menu />}\n        </Button>\n      </div>\n      <nav id={menuId} aria-label=\"Mobile\" hidden={!open} className=\"border-t px-4 pt-2 pb-4 md:hidden\">\n        <ul className=\"flex flex-col\">\n          {links.map((l) => (\n            <li key={l.label}>\n              <a href={l.href} onClick={() => setOpen(false)} className=\"block rounded-md px-2 py-2.5 text-base font-medium hover:bg-accent\">\n                {l.label}\n              </a>\n            </li>\n          ))}\n        </ul>\n        <div className=\"mt-3 grid gap-2\">\n          <a className={buttonVariants({ variant: \"outline\" })} href={secondaryAction.href}>{secondaryAction.label}</a>\n          <a className={buttonVariants()} href={primaryAction.href}>{primaryAction.label}</a>\n        </div>\n      </nav>\n    </header>\n  )\n}\n\nexport { Header1, type Header1Props }\n",
      "type": "registry:component",
      "target": "@components/ballmac/blocks/header-1/header-1.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "header",
      "navbar",
      "navigation",
      "mobile menu"
    ],
    "version": "1.0.0",
    "updated": "2026-09-28",
    "ai": {
      "summary": "The top navigation bar for a marketing site. Pass links and the two actions; it handles the mobile menu.",
      "whenToUse": [
        "Marketing sites and landing pages",
        "Docs sites with a few top-level sections"
      ],
      "whenNotToUse": [
        "Apps with deep navigation (use a sidebar)"
      ],
      "composesWith": [
        "hero-1",
        "hero-2",
        "footer-1"
      ],
      "a11y": [
        {
          "keys": "Enter / Space on the menu button",
          "action": "Opens or closes the mobile menu"
        },
        {
          "keys": "Escape",
          "action": "Closes the mobile menu"
        }
      ],
      "customization": [
        "brand, brandHref, links, secondaryAction, primaryAction props",
        "sticky: false for a static header"
      ]
    },
    "examples": [
      "header-1-demo"
    ],
    "url": "https://ui.ballmac.com/components/header-1"
  },
  "categories": [
    "blocks",
    "header"
  ],
  "type": "registry:block"
}