{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "search-field",
  "title": "Search Field",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A compact search control with a clear action, Enter callback, and preserved keyboard focus.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/i18n.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/search-field.tsx",
      "content": "// Ballmac UI: Search Field. https://ui.ballmac.com/components/search-field\n\"use client\"\n\nimport * as React from \"react\"\nimport { Search, X } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { useMessages } from \"@/lib/ballmac/i18n\"\n\ntype SearchFieldProps = Omit<\n  React.ComponentProps<\"input\">,\n  \"type\" | \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n  /** Controlled search query. */\n  value?: string\n  /** Initial query when uncontrolled. */\n  defaultValue?: string\n  /** Called whenever the query changes or clears. */\n  onValueChange?: (value: string) => void\n  /** Called when Enter submits the query. */\n  onSearch?: (value: string) => void\n  /** Accessible name of the search field. */\n  label?: string\n}\nfunction SearchField({\n  value,\n  defaultValue = \"\",\n  onValueChange,\n  onSearch,\n  label,\n  className,\n  disabled,\n  onKeyDown,\n  ...props\n}: SearchFieldProps) {\n  const msg = useMessages()\n  label ??= msg(\"search-field.label\", \"Search\")\n  const [internal, setInternal] = React.useState(defaultValue)\n  const current = value ?? internal\n  const inputRef = React.useRef<HTMLInputElement>(null)\n  function commit(next: string) {\n    if (value === undefined) setInternal(next)\n    onValueChange?.(next)\n  }\n  return (\n    <div\n      data-slot=\"search-field\"\n      className={cn(\n        \"flex h-9 w-full min-w-0 items-center gap-2 rounded-md border border-input bg-background px-3 shadow-xs transition-[border-color,box-shadow] duration-150 motion-reduce:transition-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50\",\n        className,\n      )}\n    >\n      <Search\n        aria-hidden=\"true\"\n        className=\"size-4 shrink-0 text-muted-foreground\"\n      />\n      <input\n        ref={inputRef}\n        data-slot=\"search-field-input\"\n        type=\"search\"\n        aria-label={label}\n        disabled={disabled}\n        value={current}\n        onChange={(event) => commit(event.currentTarget.value)}\n        onKeyDown={(event) => {\n          onKeyDown?.(event)\n          if (!event.defaultPrevented && event.key === \"Enter\")\n            onSearch?.(current)\n        }}\n        className=\"h-full min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50 [&::-webkit-search-cancel-button]:hidden\"\n        {...props}\n      />\n      {current && (\n        <button\n          type=\"button\"\n          aria-label={msg(\"search-field.clearSearch\", \"Clear search\")}\n          disabled={disabled}\n          onClick={() => {\n            commit(\"\")\n            inputRef.current?.focus()\n          }}\n          className=\"flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-50\"\n        >\n          <X aria-hidden=\"true\" className=\"size-4\" />\n        </button>\n      )}\n    </div>\n  )\n}\nexport { SearchField, type SearchFieldProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/search-field.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "search",
      "filter",
      "input"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "A compact search control with a clear action, Enter callback, and preserved keyboard focus.",
      "whenToUse": [
        "Filter a list or catalog",
        "Submit a query from a toolbar"
      ],
      "whenNotToUse": [
        "Use spotlight-search for site-wide command search"
      ],
      "composesWith": [
        "input"
      ],
      "a11y": [
        {
          "keys": "Enter",
          "action": "Submits the current query"
        },
        {
          "keys": "Tab / Space",
          "action": "Clears the query and returns focus"
        }
      ],
      "customization": [
        "onSearch",
        "value / defaultValue and onValueChange"
      ]
    },
    "examples": [
      "search-field-demo",
      "search-field-states"
    ],
    "url": "https://ui.ballmac.com/components/search-field"
  },
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}