{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "active-search",
  "type": "registry:ui",
  "title": "Active Search",
  "description": "A debounced live-search box (native <form role=\"search\"> + <input type=\"search\">) that filters an external results list/table as you type, with an inline loading indicator and stale-request cancellation. Submits as a normal GET search on Enter with zero JS.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/active-search.tsx",
      "type": "registry:ui",
      "target": "components/ui/active-search.tsx",
      "content": "/** @jsxImportSource hono/jsx */\nimport type { Child } from \"hono/jsx\"\nimport { cn, type ClassValue } from \"@/registry/lib/cn\"\n\n// Active Search — shadcn-htmx, htmx v4 + Tailwind v4.\n//\n// A debounced live-search box that filters an external results list/table as\n// the user types, with an inline loading indicator and stale-request\n// cancellation. It degrades to a normal GET search on Enter when JS is off.\n//\n// **Native-first.** The control is a real <form> wrapping <input type=\"search\">.\n//   - The <form action> means Enter submits a normal navigation search with\n//     zero JS — progressive enhancement, not emulation.\n//   - <input type=\"search\"> gives the platform clear-field affordance + a\n//     `search` event that fires on Enter and when the field is cleared.\n//     We add `search` to hx-trigger so clearing re-runs the filter.\n//     See repos/mdn/files/en-us/web/html/reference/elements/input/search/index.md\n//        repos/mdn/files/en-us/web/api/htmlinputelement/search_event/index.md\n//\n// htmx wiring (verified against the vendored v4 source):\n//   - hx-trigger=\"input changed delay:Nms, search\" — `input changed delay`\n//     debounces keystrokes and ignores no-op keys (arrows); the `search`\n//     event covers Enter + the native clear button.\n//     See repos/htmx/www/src/content/reference/01-attributes/06-hx-trigger.md\n//        repos/htmx/www/src/content/patterns/02-forms/01-active-search.md\n//   - hx-sync=\"this:replace\" — aborts the in-flight request and replaces it\n//     with the latest one, so stale responses never clobber fresh input.\n//     See repos/htmx/www/src/content/reference/01-attributes/21-hx-sync.md\n//   - hx-indicator — htmx toggles the `.htmx-request` class on the indicator\n//     while a request is in flight; we drive an opacity transition off it.\n//     See repos/htmx/www/src/content/reference/01-attributes/19-hx-indicator.md\n//\n// No custom JS: the debounce, cancellation, and indicator are all htmx; the\n// no-JS fallback is the native <form>. data-slot is for styling/testing hooks.\n\nconst formBase = \"relative w-full\"\n\nconst inputBase =\n  \"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent py-1 pr-9 pl-9 text-base shadow-xs transition-[color,box-shadow] outline-none \" +\n  \"selection:bg-primary selection:text-primary-foreground \" +\n  \"placeholder:text-muted-foreground \" +\n  \"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 \" +\n  \"md:text-sm dark:bg-input/30 \" +\n  \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 \" +\n  \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 \" +\n  // Hide the WebKit clear button — htmx's `search` trigger + our spinner is\n  // the affordance, and the native X overlaps the indicator.\n  \"[&::-webkit-search-cancel-button]:hidden\"\n\n// Leading magnifier icon, centred in the left padding gutter.\nconst searchIconClass =\n  \"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n\n// Trailing spinner. `htmx-indicator` is hidden by default; htmx adds\n// `.htmx-request` to it (via hx-indicator) while the request is in flight,\n// fading it in. role=status + aria-live=\"polite\" announces \"Searching…\" to\n// assistive tech without stealing focus.\nconst indicatorClass =\n  \"htmx-indicator pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\"\n\nexport type ActiveSearchProps = {\n  // Input id (and the base for the indicator id: `${id}-indicator`).\n  id: string\n  name?: string\n  placeholder?: string\n  value?: string\n  // No-JS fallback: where the <form> navigates on Enter when htmx is absent.\n  // Also the htmx request URL when hx-get isn't passed explicitly.\n  action?: string\n  // GET keeps the search idempotent and the no-JS fallback shareable as a URL.\n  method?: \"get\" | \"post\"\n  // Debounce window for the `input` trigger. Default 300ms.\n  delay?: number\n  required?: boolean\n  disabled?: boolean\n  autofocus?: boolean\n  // Visible loading text for screen readers (defaults to \"Searching…\").\n  loadingLabel?: string\n  ariaLabel?: string\n  ariaLabelledby?: string\n  ariaDescribedby?: string\n  class?: ClassValue\n  inputClass?: ClassValue\n  // Optional extra content rendered after the input inside the <form>\n  // (e.g. a visually-hidden submit button for no-JS keyboards). Usually unused.\n  children?: Child\n  // htmx attrs ride onto the <input>. Typical setup:\n  //   hx-get=\"/search\"  hx-target=\"#results\"  hx-swap=\"innerHTML\"\n  // hx-trigger / hx-sync / hx-indicator are supplied with sensible defaults\n  // below but can be overridden by passing them explicitly.\n  [key: `hx-${string}`]: any\n  [key: `data-${string}`]: any\n}\n\nexport function ActiveSearch(props: ActiveSearchProps) {\n  const {\n    id,\n    name = \"q\",\n    placeholder = \"Search…\",\n    value,\n    action,\n    method = \"get\",\n    delay = 300,\n    required,\n    disabled,\n    autofocus,\n    loadingLabel = \"Searching…\",\n    ariaLabel,\n    ariaLabelledby,\n    ariaDescribedby,\n    class: className,\n    inputClass,\n    children,\n    ...rest\n  } = props\n\n  const indicatorId = `${id}-indicator`\n\n  // Defaults that make the search \"active\". Anything passed in `rest`\n  // (hx-trigger / hx-sync / hx-indicator / hx-get …) overrides these.\n  const hxDefaults: Record<string, any> = {\n    \"hx-get\": action,\n    \"hx-trigger\": `input changed delay:${delay}ms, search`,\n    \"hx-sync\": \"this:replace\",\n    \"hx-indicator\": `#${indicatorId}`,\n  }\n  const hx = { ...hxDefaults, ...rest }\n\n  return (\n    <form\n      data-slot=\"active-search\"\n      role=\"search\"\n      class={cn(formBase, className)}\n      action={action}\n      method={method}\n    >\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\"\n        viewBox=\"0 0 24 24\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        stroke-width=\"2\"\n        stroke-linecap=\"round\"\n        stroke-linejoin=\"round\"\n        class={searchIconClass}\n        aria-hidden=\"true\"\n      >\n        <circle cx=\"11\" cy=\"11\" r=\"8\" />\n        <path d=\"m21 21-4.3-4.3\" />\n      </svg>\n      <input\n        type=\"search\"\n        id={id}\n        name={name}\n        value={value}\n        placeholder={placeholder}\n        required={required}\n        disabled={disabled}\n        autofocus={autofocus}\n        autocomplete=\"off\"\n        // Mobile: label the Enter key \"search\" and show the search keyboard.\n        enterkeyhint=\"search\"\n        inputmode=\"search\"\n        aria-label={ariaLabel}\n        aria-labelledby={ariaLabelledby}\n        aria-describedby={ariaDescribedby}\n        data-slot=\"active-search-input\"\n        class={cn(inputBase, inputClass)}\n        {...hx}\n      />\n      <span\n        id={indicatorId}\n        data-slot=\"active-search-indicator\"\n        role=\"status\"\n        aria-live=\"polite\"\n        class={indicatorClass}\n      >\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          stroke-width=\"2\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n          class=\"size-4 animate-spin\"\n          aria-hidden=\"true\"\n        >\n          <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n        </svg>\n        <span class=\"sr-only\">{loadingLabel}</span>\n      </span>\n      {children}\n    </form>\n  )\n}\n"
    },
    {
      "path": "registry/jinja2/active-search.html",
      "type": "registry:file",
      "target": "templates/components/active-search.html",
      "content": "{# Active Search macro — shadcn-htmx, htmx v4 + Tailwind v4.\n   Debounced live-search box that filters an external results list/table as\n   you type, with an inline loading indicator and stale-request cancellation.\n   Submits as a normal GET search on Enter when JS is off (native <form action>).\n\n   Native-first: <form role=\"search\"> wraps <input type=\"search\">. The\n   `search` event fires on Enter + native clear, so it's added to hx-trigger.\n     repos/mdn/files/en-us/web/html/reference/elements/input/search/index.md\n     repos/mdn/files/en-us/web/api/htmlinputelement/search_event/index.md\n   htmx wiring:\n     hx-trigger=\"input changed delay:Nms, search\"  (debounce + clear/Enter)\n       repos/htmx/www/src/content/reference/01-attributes/06-hx-trigger.md\n     hx-sync=\"this:replace\"  (abort in-flight, use the latest request)\n       repos/htmx/www/src/content/reference/01-attributes/21-hx-sync.md\n     hx-indicator=\"#{id}-indicator\"  (.htmx-request fades the spinner in)\n       repos/htmx/www/src/content/reference/01-attributes/19-hx-indicator.md\n\n   Usage:\n     {% from \"components/active-search.html\" import active_search %}\n     {{ active_search(id=\"search\", action=\"/search\", placeholder=\"Search contacts…\",\n                      hx_get=\"/search\", hx_target=\"#results\", hx_swap=\"innerHTML\") }}\n     <tbody id=\"results\"></tbody>\n#}\n\n{% macro active_search(\n    id,\n    name=\"q\",\n    placeholder=\"Search…\",\n    value=none,\n    action=none,\n    method=\"get\",\n    delay=300,\n    required=false,\n    disabled=false,\n    autofocus=false,\n    loading_label=\"Searching…\",\n    aria_label=none,\n    aria_labelledby=none,\n    aria_describedby=none,\n    extra_class=\"\",\n    input_class=\"\",\n    **attrs\n) %}\n<form data-slot=\"active-search\" role=\"search\" class=\"relative w-full {{ extra_class }}\"\n      {%- if action %} action=\"{{ action }}\"{% endif %} method=\"{{ method }}\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n       stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n       class=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n       aria-hidden=\"true\">\n    <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n    <path d=\"m21 21-4.3-4.3\"></path>\n  </svg>\n  <input\n    type=\"search\"\n    id=\"{{ id }}\"\n    name=\"{{ name }}\"\n    {%- if value is not none %} value=\"{{ value }}\"{% endif %}\n    {%- if placeholder %} placeholder=\"{{ placeholder }}\"{% endif %}\n    {%- if required %} required{% endif %}\n    {%- if disabled %} disabled{% endif %}\n    {%- if autofocus %} autofocus{% endif %}\n    {%- if aria_label %} aria-label=\"{{ aria_label }}\"{% endif %}\n    {%- if aria_labelledby %} aria-labelledby=\"{{ aria_labelledby }}\"{% endif %}\n    {%- if aria_describedby %} aria-describedby=\"{{ aria_describedby }}\"{% endif %}\n    autocomplete=\"off\"\n    enterkeyhint=\"search\"\n    inputmode=\"search\"\n    data-slot=\"active-search-input\"\n    {%- if \"hx_get\" not in attrs and action %} hx-get=\"{{ action }}\"{% endif %}\n    {%- if \"hx_trigger\" not in attrs %} hx-trigger=\"input changed delay:{{ delay }}ms, search\"{% endif %}\n    {%- if \"hx_sync\" not in attrs %} hx-sync=\"this:replace\"{% endif %}\n    {%- if \"hx_indicator\" not in attrs %} hx-indicator=\"#{{ id }}-indicator\"{% endif %}\n    class=\"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent py-1 pr-9 pl-9 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&::-webkit-search-cancel-button]:hidden {{ input_class }}\"\n    {%- for k, v in attrs.items() %} {{ k|replace('_', '-') }}=\"{{ v }}\"{% endfor -%}\n  >\n  <span id=\"{{ id }}-indicator\" data-slot=\"active-search-indicator\" role=\"status\" aria-live=\"polite\"\n        class=\"htmx-indicator pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n         stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n         class=\"size-4 animate-spin\" aria-hidden=\"true\">\n      <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n    </svg>\n    <span class=\"sr-only\">{{ loading_label }}</span>\n  </span>\n  {% if caller %}{{ caller() }}{% endif %}\n</form>\n{% endmacro %}\n"
    },
    {
      "path": "registry/go-templates/active-search.tmpl",
      "type": "registry:file",
      "target": "components/active-search.tmpl",
      "content": "{{/*\n  Active Search template — shadcn-htmx, htmx v4 + Tailwind v4.\n  Debounced live-search box that filters an external results list/table as\n  you type, with an inline loading indicator and stale-request cancellation.\n  Submits as a normal GET search on Enter when JS is off (native <form action>).\n\n  Native-first: <form role=\"search\"> wraps <input type=\"search\">. The\n  `search` event fires on Enter + native clear, so it's added to hx-trigger.\n    repos/mdn/files/en-us/web/html/reference/elements/input/search/index.md\n    repos/mdn/files/en-us/web/api/htmlinputelement/search_event/index.md\n  htmx wiring:\n    hx-trigger=\"input changed delay:Nms, search\"  (debounce + clear/Enter)\n      repos/htmx/www/src/content/reference/01-attributes/06-hx-trigger.md\n    hx-sync=\"this:replace\"  (abort in-flight, use the latest request)\n      repos/htmx/www/src/content/reference/01-attributes/21-hx-sync.md\n    hx-indicator=\"#{ID}-indicator\"  (.htmx-request fades the spinner in)\n      repos/htmx/www/src/content/reference/01-attributes/19-hx-indicator.md\n\n      type ActiveSearchArgs struct {\n          ID, Name, Placeholder, Value, Action, Method string\n          Delay int            // debounce ms; default 300\n          Required, Disabled, Autofocus bool\n          LoadingLabel string  // sr-only loading text; default \"Searching…\"\n          AriaLabel, AriaLabelledby, AriaDescribedby string\n          // htmx target/swap for the results container.\n          HxGet, HxTarget, HxSwap string\n      }\n\n  Usage:\n    {{template \"active-search\" (dict \"ID\" \"search\" \"Action\" \"/search\"\n      \"Placeholder\" \"Search contacts…\" \"HxGet\" \"/search\"\n      \"HxTarget\" \"#results\" \"HxSwap\" \"innerHTML\")}}\n*/}}\n\n{{define \"active-search\"}}\n{{- $name := or .Name \"q\" -}}\n{{- $placeholder := or .Placeholder \"Search…\" -}}\n{{- $method := or .Method \"get\" -}}\n{{- $delay := or .Delay 300 -}}\n{{- $loading := or .LoadingLabel \"Searching…\" -}}\n{{- $hxGet := or .HxGet .Action -}}\n<form data-slot=\"active-search\" role=\"search\" class=\"relative w-full\"\n      {{if .Action}}action=\"{{.Action}}\"{{end}} method=\"{{$method}}\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n       stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n       class=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n       aria-hidden=\"true\">\n    <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n    <path d=\"m21 21-4.3-4.3\"></path>\n  </svg>\n  <input type=\"search\" id=\"{{.ID}}\" name=\"{{$name}}\"\n         {{if .Value}}value=\"{{.Value}}\"{{end}}\n         placeholder=\"{{$placeholder}}\"\n         {{if .Required}}required{{end}} {{if .Disabled}}disabled{{end}}\n         {{if .Autofocus}}autofocus{{end}}\n         {{if .AriaLabel}}aria-label=\"{{.AriaLabel}}\"{{end}}\n         {{if .AriaLabelledby}}aria-labelledby=\"{{.AriaLabelledby}}\"{{end}}\n         {{if .AriaDescribedby}}aria-describedby=\"{{.AriaDescribedby}}\"{{end}}\n         autocomplete=\"off\" enterkeyhint=\"search\" inputmode=\"search\"\n         data-slot=\"active-search-input\"\n         {{if $hxGet}}hx-get=\"{{$hxGet}}\"{{end}}\n         hx-trigger=\"input changed delay:{{$delay}}ms, search\"\n         hx-sync=\"this:replace\"\n         hx-indicator=\"#{{.ID}}-indicator\"\n         {{if .HxTarget}}hx-target=\"{{.HxTarget}}\"{{end}}\n         {{if .HxSwap}}hx-swap=\"{{.HxSwap}}\"{{end}}\n         class=\"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent py-1 pr-9 pl-9 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&::-webkit-search-cancel-button]:hidden\">\n  <span id=\"{{.ID}}-indicator\" data-slot=\"active-search-indicator\" role=\"status\" aria-live=\"polite\"\n        class=\"htmx-indicator pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n         stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n         class=\"size-4 animate-spin\" aria-hidden=\"true\">\n      <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n    </svg>\n    <span class=\"sr-only\">{{$loading}}</span>\n  </span>\n</form>\n{{end}}\n"
    },
    {
      "path": "registry/phoenix/active_search.ex",
      "type": "registry:file",
      "target": "lib/my_app_web/components/active_search.ex",
      "content": "defmodule ShadcnHtmx.Components.ActiveSearch do\n  @moduledoc \"\"\"\n  Active Search — shadcn-htmx, htmx v4 + Tailwind v4 for Phoenix.\n\n  A debounced live-search box that filters an external results list/table as\n  the user types, with an inline loading indicator and stale-request\n  cancellation. Submits as a normal GET search on Enter when JS is off\n  (native `<form action>`).\n\n  Native-first: `<form role=\"search\">` wraps `<input type=\"search\">`. The\n  `search` event fires on Enter + the native clear button, so it's added to\n  `hx-trigger`.\n\n    * repos/mdn/files/en-us/web/html/reference/elements/input/search/index.md\n    * repos/mdn/files/en-us/web/api/htmlinputelement/search_event/index.md\n\n  htmx wiring:\n\n    * `hx-trigger=\"input changed delay:Nms, search\"` — debounce + clear/Enter.\n      repos/htmx/www/src/content/reference/01-attributes/06-hx-trigger.md\n    * `hx-sync=\"this:replace\"` — abort the in-flight request, use the latest.\n      repos/htmx/www/src/content/reference/01-attributes/21-hx-sync.md\n    * `hx-indicator=\"#{id}-indicator\"` — htmx adds `.htmx-request`; the spinner\n      fades in. repos/htmx/www/src/content/reference/01-attributes/19-hx-indicator.md\n\n  ## Examples\n\n      <.active_search id=\"search\" action={~p\"/search\"} placeholder=\"Search contacts…\"\n        hx-get={~p\"/search\"} hx-target=\"#results\" hx-swap=\"innerHTML\" />\n      <tbody id=\"results\"></tbody>\n  \"\"\"\n\n  use Phoenix.Component\n\n  attr :id, :string, required: true\n  attr :name, :string, default: \"q\"\n  attr :placeholder, :string, default: \"Search…\"\n  attr :value, :string, default: nil\n  attr :action, :string, default: nil\n  attr :method, :string, default: \"get\"\n  attr :delay, :integer, default: 300\n  attr :required, :boolean, default: false\n  attr :disabled, :boolean, default: false\n  attr :autofocus, :boolean, default: false\n  attr :loading_label, :string, default: \"Searching…\"\n  attr :\"aria-label\", :string, default: nil\n  attr :\"aria-labelledby\", :string, default: nil\n  attr :\"aria-describedby\", :string, default: nil\n  attr :class, :string, default: nil\n\n  attr :rest, :global,\n    include: ~w(hx-get hx-post hx-trigger hx-sync hx-target hx-swap hx-indicator hx-vals hx-include)\n\n  def active_search(assigns) do\n    ~H\"\"\"\n    <form\n      data-slot=\"active-search\"\n      role=\"search\"\n      class={[\"relative w-full\", @class]}\n      action={@action}\n      method={@method}\n    >\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\"\n        viewBox=\"0 0 24 24\"\n        fill=\"none\"\n        stroke=\"currentColor\"\n        stroke-width=\"2\"\n        stroke-linecap=\"round\"\n        stroke-linejoin=\"round\"\n        class=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n        aria-hidden=\"true\"\n      >\n        <circle cx=\"11\" cy=\"11\" r=\"8\" />\n        <path d=\"m21 21-4.3-4.3\" />\n      </svg>\n      <input\n        type=\"search\"\n        id={@id}\n        name={@name}\n        value={@value}\n        placeholder={@placeholder}\n        required={@required}\n        disabled={@disabled}\n        autofocus={@autofocus}\n        autocomplete=\"off\"\n        enterkeyhint=\"search\"\n        inputmode=\"search\"\n        aria-label={assigns[:\"aria-label\"]}\n        aria-labelledby={assigns[:\"aria-labelledby\"]}\n        aria-describedby={assigns[:\"aria-describedby\"]}\n        data-slot=\"active-search-input\"\n        hx-get={@action}\n        hx-trigger={\"input changed delay:#{@delay}ms, search\"}\n        hx-sync=\"this:replace\"\n        hx-indicator={\"##{@id}-indicator\"}\n        class=\"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent py-1 pr-9 pl-9 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&::-webkit-search-cancel-button]:hidden\"\n        {@rest}\n      />\n      <span\n        id={\"#{@id}-indicator\"}\n        data-slot=\"active-search-indicator\"\n        role=\"status\"\n        aria-live=\"polite\"\n        class=\"htmx-indicator pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\"\n      >\n        <svg\n          xmlns=\"http://www.w3.org/2000/svg\"\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          stroke-width=\"2\"\n          stroke-linecap=\"round\"\n          stroke-linejoin=\"round\"\n          class=\"size-4 animate-spin\"\n          aria-hidden=\"true\"\n        >\n          <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n        </svg>\n        <span class=\"sr-only\">{@loading_label}</span>\n      </span>\n    </form>\n    \"\"\"\n  end\nend\n"
    },
    {
      "path": "registry/html/active-search.html",
      "type": "registry:file",
      "target": "snippets/active-search.html",
      "content": "<!--\n  shadcn-htmx — raw HTML active-search snippet.\n\n  Debounced live-search box that filters an external results list/table as\n  you type, with an inline loading indicator and stale-request cancellation.\n  Submits as a normal GET search on Enter when JS is off (native <form action>).\n\n  Native-first: <form role=\"search\"> wraps <input type=\"search\">. The\n  `search` event fires on Enter + the native clear button, so it's in\n  hx-trigger alongside the debounced `input` trigger.\n    - hx-trigger=\"input changed delay:300ms, search\"  (debounce + clear/Enter)\n    - hx-sync=\"this:replace\"      (abort in-flight, use the latest request)\n    - hx-indicator=\"#search-indicator\"  (.htmx-request fades the spinner in)\n\n  Wire hx-target at your results container; the server returns the rows/list.\n  Relies only on theme tokens — no app CSS beyond Tailwind + the htmx-indicator\n  class (htmx ships its default opacity transition for it).\n-->\n\n<form data-slot=\"active-search\" role=\"search\" class=\"relative w-full\"\n      action=\"/search\" method=\"get\">\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n       stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n       class=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground\"\n       aria-hidden=\"true\">\n    <circle cx=\"11\" cy=\"11\" r=\"8\"></circle>\n    <path d=\"m21 21-4.3-4.3\"></path>\n  </svg>\n  <input type=\"search\" id=\"search\" name=\"q\"\n         placeholder=\"Search contacts…\"\n         autocomplete=\"off\" enterkeyhint=\"search\" inputmode=\"search\"\n         data-slot=\"active-search-input\"\n         hx-get=\"/search\"\n         hx-trigger=\"input changed delay:300ms, search\"\n         hx-sync=\"this:replace\"\n         hx-indicator=\"#search-indicator\"\n         hx-target=\"#results\"\n         hx-swap=\"innerHTML\"\n         class=\"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent py-1 pr-9 pl-9 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&::-webkit-search-cancel-button]:hidden\">\n  <span id=\"search-indicator\" data-slot=\"active-search-indicator\" role=\"status\" aria-live=\"polite\"\n        class=\"htmx-indicator pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground\">\n    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n         stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n         class=\"size-4 animate-spin\" aria-hidden=\"true\">\n      <path d=\"M21 12a9 9 0 1 1-6.219-8.56\"></path>\n    </svg>\n    <span class=\"sr-only\">Searching…</span>\n  </span>\n</form>\n\n<!-- Results container the search targets. Server returns the rows on each query. -->\n<tbody id=\"results\"></tbody>\n"
    }
  ]
}
