{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "exclusive-accordion",
  "type": "registry:ui",
  "title": "Exclusive Accordion",
  "description": "Scriptless single-open accordion: multiple native <details> elements share one `name` attribute so opening one auto-closes the others — the pure-HTML exclusive variant of the APG-scripted accordion. Zero JavaScript; the exclusivity survives with JS disabled. Ships in five flavours: Hono JSX (TypeScript), Jinja2 macros, Go html/template, Phoenix function component, and a raw HTML snippet.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/exclusive-accordion.tsx",
      "type": "registry:ui",
      "target": "components/ui/exclusive-accordion.tsx",
      "content": "/** @jsxImportSource hono/jsx */\nimport type { PropsWithChildren } from \"hono/jsx\"\nimport { cn, type ClassValue } from \"@/registry/lib/cn\"\n\n// Exclusive Accordion — shadcn-htmx, htmx v4 + Tailwind v4.\n//\n// The scriptless, single-open accordion. Several <details> elements share one\n// `name` attribute, so the browser keeps exactly one open at a time: opening\n// any item auto-closes the others. This is the pure-HTML exclusive variant of\n// the APG-scripted accordion — ZERO JavaScript, no boot script, no site.js.\n//\n// shadcn upstream uses Radix Accordion (a JS state machine wiring buttons +\n// regions with aria-expanded / aria-controls). We let the platform do it:\n//   - Click / Space / Enter toggles open (browser default on <summary>).\n//   - <summary> is implicitly role=\"button\", focusable, with its text as the\n//     accessible name; the browser sets aria-expanded to mirror `open`.\n//   - <details name=\"...\"> makes the group mutually exclusive natively. Per the\n//     HTML spec, if more than one grouped item carries `open`, only the FIRST\n//     in source order renders open — so we never produce an invalid state.\n//\n// This component differs from registry/ui/accordion.tsx (type=\"single\"), which\n// assigns the grouping `name` at runtime via public/site.js and layers the APG\n// arrow-key contract on top. ExclusiveAccordion renders the `name` straight\n// into the server HTML, so the exclusivity survives with JS disabled and there\n// is no keyboard contract beyond what <summary> ships natively (Tab to focus,\n// Enter / Space to toggle). That makes it the right pick for progressive-\n// enhancement-first surfaces (docs FAQs, server-rendered settings panels).\n//\n// Refs:\n//   repos/mdn/files/en-us/web/html/reference/elements/details/index.md\n//     (`name` attribute — \"give multiple <details> the same name value to\n//      group them. Only one of the grouped <details> can be open at a time …\n//      if multiple are given `open`, only the first in source order renders\n//      open.\" Also: `open` boolean, the `toggle` event, implicit role=group.)\n//   repos/mdn/files/en-us/web/html/reference/elements/summary/index.md\n//     (click / Space toggles parent <details>; display:list-item marker.)\n//   repos/aria-practices/content/patterns/accordion/ (the scripted contract we\n//     deliberately do NOT emulate here — see the note above.)\n//   repos/aria-practices/content/patterns/disclosure/ (native <details> is a\n//     disclosure widget; aria-controls is optional.)\n\ntype ExclusiveAccordionProps = PropsWithChildren<{\n  // Shared group name written onto every item's <details name>. Required —\n  // it is what makes the group exclusive. Distinct accordions on one page\n  // must use distinct names or they'd close each other.\n  name: string\n  class?: ClassValue\n}>\n\nexport function ExclusiveAccordion(props: ExclusiveAccordionProps) {\n  const { name, class: className, children, ...rest } = props\n  return (\n    <div\n      data-slot=\"exclusive-accordion\"\n      data-name={name}\n      class={cn(\"w-full\", className)}\n      {...rest}\n    >\n      {children}\n    </div>\n  )\n}\n\ntype ExclusiveAccordionItemProps = PropsWithChildren<{\n  // The shared group name. Pass the SAME value as the parent's `name`.\n  name: string\n  // Distinct identifier per item, emitted as data-value for targeting.\n  value?: string\n  // Pre-open this item on initial render. If two items in the group set this,\n  // the browser opens only the first in source order (HTML spec).\n  open?: boolean\n  disabled?: boolean\n  class?: ClassValue\n}>\n\nexport function ExclusiveAccordionItem(props: ExclusiveAccordionItemProps) {\n  const { name, value, open, disabled, class: className, children, ...rest } =\n    props\n  return (\n    <details\n      data-slot=\"exclusive-accordion-item\"\n      data-value={value}\n      data-disabled={disabled ? \"true\" : undefined}\n      name={name}\n      open={open}\n      class={cn(\n        \"border-b last:border-b-0\",\n        disabled && \"pointer-events-none opacity-50\",\n        className,\n      )}\n      {...rest}\n    >\n      {children}\n    </details>\n  )\n}\n\ntype ExclusiveAccordionTriggerProps = PropsWithChildren<{ class?: ClassValue }>\n\nexport function ExclusiveAccordionTrigger(\n  props: ExclusiveAccordionTriggerProps,\n) {\n  const { class: className, children, ...rest } = props\n  return (\n    <summary\n      data-slot=\"exclusive-accordion-trigger\"\n      class={cn(\n        \"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden \" +\n          \"hover:underline \" +\n          \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 \" +\n          \"list-none [&::-webkit-details-marker]:hidden \" +\n          // Rotate the chevron when the parent <details> is open.\n          \"[details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\",\n        className,\n      )}\n      {...rest}\n    >\n      {children}\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        data-slot=\"exclusive-accordion-chevron\"\n        class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\"\n        aria-hidden=\"true\"\n      >\n        <polyline points=\"6 9 12 15 18 9\" />\n      </svg>\n    </summary>\n  )\n}\n\ntype ExclusiveAccordionContentProps = PropsWithChildren<{ class?: ClassValue }>\n\nexport function ExclusiveAccordionContent(\n  props: ExclusiveAccordionContentProps,\n) {\n  const { class: className, children, ...rest } = props\n  return (\n    <div\n      data-slot=\"exclusive-accordion-content\"\n      class={cn(\"overflow-hidden pt-0 pb-4 text-sm\", className)}\n      {...rest}\n    >\n      {children}\n    </div>\n  )\n}\n"
    },
    {
      "path": "registry/jinja2/exclusive-accordion.html",
      "type": "registry:file",
      "target": "templates/components/exclusive-accordion.html",
      "content": "{# Exclusive Accordion macros — shadcn-htmx, htmx v4 + Tailwind v4.\n   Mirrors registry/ui/exclusive-accordion.tsx EXACTLY.\n\n   The scriptless single-open accordion: every <details> shares one `name`\n   attribute, so the browser keeps exactly one open at a time — opening one\n   auto-closes the others. ZERO JavaScript: no boot script, no site.js. Per\n   the HTML spec, if multiple grouped items carry `open`, only the first in\n   source order renders open.\n\n   Ref: repos/mdn/files/en-us/web/html/reference/elements/details/index.md (name)\n\n   Usage:\n     {% from \"components/exclusive-accordion.html\" import\n        exclusive_accordion_open, exclusive_accordion_close,\n        exclusive_accordion_item_open, exclusive_accordion_item_close,\n        exclusive_accordion_trigger,\n        exclusive_accordion_content_open, exclusive_accordion_content_close %}\n\n     {{ exclusive_accordion_open(name=\"faq\") }}\n       {{ exclusive_accordion_item_open(name=\"faq\", value=\"q1\", open=true) }}\n         {{ exclusive_accordion_trigger(\"What's htmx?\") }}\n         {{ exclusive_accordion_content_open() }}\n           Hypermedia-driven HTML extensions.\n         {{ exclusive_accordion_content_close() }}\n       {{ exclusive_accordion_item_close() }}\n     {{ exclusive_accordion_close() }} #}\n\n{% macro exclusive_accordion_open(name, extra_class=\"\") -%}\n<div data-slot=\"exclusive-accordion\" data-name=\"{{ name }}\" class=\"w-full {{ extra_class }}\">\n{%- endmacro %}\n\n{% macro exclusive_accordion_close() %}</div>{% endmacro %}\n\n{% macro exclusive_accordion_item_open(name, value=\"\", open=false, disabled=false, extra_class=\"\") -%}\n<details data-slot=\"exclusive-accordion-item\"\n         {%- if value %} data-value=\"{{ value }}\"{% endif %}\n         {%- if disabled %} data-disabled=\"true\"{% endif %}\n         name=\"{{ name }}\"\n         {%- if open %} open{% endif %}\n         class=\"border-b last:border-b-0 {% if disabled %}pointer-events-none opacity-50{% endif %} {{ extra_class }}\">\n{%- endmacro %}\n\n{% macro exclusive_accordion_item_close() %}</details>{% endmacro %}\n\n{% macro exclusive_accordion_trigger(text, extra_class=\"\") -%}\n<summary data-slot=\"exclusive-accordion-trigger\"\n  class=\"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 list-none [&::-webkit-details-marker]:hidden [details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180 {{ extra_class }}\">\n  {{ text }}\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n       data-slot=\"exclusive-accordion-chevron\"\n       class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\" aria-hidden=\"true\">\n    <polyline points=\"6 9 12 15 18 9\" />\n  </svg>\n</summary>\n{%- endmacro %}\n\n{% macro exclusive_accordion_content_open(extra_class=\"\") -%}\n<div data-slot=\"exclusive-accordion-content\" class=\"overflow-hidden pt-0 pb-4 text-sm {{ extra_class }}\">\n{%- endmacro %}\n\n{% macro exclusive_accordion_content_close() %}</div>{% endmacro %}\n"
    },
    {
      "path": "registry/go-templates/exclusive-accordion.tmpl",
      "type": "registry:file",
      "target": "components/exclusive-accordion.tmpl",
      "content": "{{/*\n  Exclusive Accordion templates — shadcn-htmx, htmx v4 + Tailwind v4.\n  Mirrors registry/ui/exclusive-accordion.tsx EXACTLY.\n\n  The scriptless single-open accordion: every <details> shares one `name`\n  attribute, so the browser keeps exactly one open at a time — opening one\n  auto-closes the others. ZERO JavaScript. Per the HTML spec, if multiple\n  grouped items carry `open`, only the first in source order renders open.\n\n  Ref: repos/mdn/files/en-us/web/html/reference/elements/details (name)\n\n  Three named templates compose:\n    - \"exclusive_accordion\"          — wrapper open/close (call with Name + Body)\n    - \"exclusive_accordion_item\"     — single <details name> with summary + content\n    - \"exclusive_accordion_trigger\"  — just the <summary> (when composing manually)\n\n  Usage:\n    {{template \"exclusive_accordion\" (dict\n      \"Name\" \"faq\"\n      \"Body\" (htmlSafe `\n        {{template \"exclusive_accordion_item\" (dict\n          \"Name\" \"faq\" \"Value\" \"q1\" \"Title\" \"What's htmx?\" \"Open\" true\n          \"Body\" (htmlSafe \"Hypermedia-driven HTML extensions.\")\n        )}}`)\n    )}}\n*/}}\n\n{{define \"exclusive_accordion\"}}\n<div data-slot=\"exclusive-accordion\" data-name=\"{{.Name}}\" class=\"w-full\">\n  {{.Body}}\n</div>\n{{end}}\n\n{{define \"exclusive_accordion_item\"}}\n<details data-slot=\"exclusive-accordion-item\"\n         {{if .Value}}data-value=\"{{.Value}}\"{{end}}\n         {{if .Disabled}}data-disabled=\"true\"{{end}}\n         name=\"{{.Name}}\"\n         {{if .Open}}open{{end}}\n         class=\"border-b last:border-b-0\">\n  {{template \"exclusive_accordion_trigger\" (dict \"Text\" .Title)}}\n  <div data-slot=\"exclusive-accordion-content\" class=\"overflow-hidden pt-0 pb-4 text-sm\">{{.Body}}</div>\n</details>\n{{end}}\n\n{{define \"exclusive_accordion_trigger\"}}\n<summary data-slot=\"exclusive-accordion-trigger\"\n  class=\"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 list-none [&::-webkit-details-marker]:hidden [details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\">\n  {{.Text}}\n  <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n       data-slot=\"exclusive-accordion-chevron\"\n       class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\" aria-hidden=\"true\">\n    <polyline points=\"6 9 12 15 18 9\" />\n  </svg>\n</summary>\n{{end}}\n"
    },
    {
      "path": "registry/phoenix/exclusive_accordion.ex",
      "type": "registry:file",
      "target": "lib/my_app_web/components/exclusive_accordion.ex",
      "content": "defmodule ShadcnHtmx.Components.ExclusiveAccordion do\n  @moduledoc \"\"\"\n  Exclusive Accordion — shadcn-htmx, htmx v4 + Tailwind v4 for Phoenix.\n  Mirrors registry/ui/exclusive-accordion.tsx EXACTLY.\n\n  The scriptless single-open accordion. Several `<details>` elements share one\n  `name` attribute, so the browser keeps exactly one open at a time — opening\n  one auto-closes the others. ZERO JavaScript: no boot script, no site.js. Per\n  the HTML spec, if multiple grouped items carry `open`, only the first in\n  source order renders open.\n\n  Ref: repos/mdn/files/en-us/web/html/reference/elements/details (name)\n\n  ## Examples\n\n      <.exclusive_accordion name=\"faq\">\n        <.exclusive_accordion_item name=\"faq\" value=\"q1\" open>\n          <.exclusive_accordion_trigger>What's htmx?</.exclusive_accordion_trigger>\n          <.exclusive_accordion_content>Hypermedia-driven HTML extensions.</.exclusive_accordion_content>\n        </.exclusive_accordion_item>\n      </.exclusive_accordion>\n  \"\"\"\n\n  use Phoenix.Component\n\n  attr :name, :string, required: true\n  attr :class, :string, default: nil\n  slot :inner_block, required: true\n\n  def exclusive_accordion(assigns) do\n    ~H\"\"\"\n    <div\n      data-slot=\"exclusive-accordion\"\n      data-name={@name}\n      class={[\"w-full\", @class]}\n    >\n      {render_slot(@inner_block)}\n    </div>\n    \"\"\"\n  end\n\n  attr :name, :string, required: true\n  attr :value, :string, default: nil\n  attr :open, :boolean, default: false\n  attr :disabled, :boolean, default: false\n  attr :class, :string, default: nil\n  slot :inner_block, required: true\n\n  def exclusive_accordion_item(assigns) do\n    ~H\"\"\"\n    <details\n      data-slot=\"exclusive-accordion-item\"\n      data-value={@value}\n      data-disabled={@disabled && \"true\"}\n      name={@name}\n      open={@open}\n      class={[\n        \"border-b last:border-b-0\",\n        @disabled && \"pointer-events-none opacity-50\",\n        @class\n      ]}\n    >\n      {render_slot(@inner_block)}\n    </details>\n    \"\"\"\n  end\n\n  attr :class, :string, default: nil\n  slot :inner_block, required: true\n\n  def exclusive_accordion_trigger(assigns) do\n    ~H\"\"\"\n    <summary\n      data-slot=\"exclusive-accordion-trigger\"\n      class={[\n        \"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium\",\n        \"transition-all outline-none select-none marker:hidden hover:underline\",\n        \"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n        \"list-none [&::-webkit-details-marker]:hidden\",\n        \"[details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\",\n        @class\n      ]}\n    >\n      {render_slot(@inner_block)}\n      <svg\n        xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\"\n        stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n        data-slot=\"exclusive-accordion-chevron\"\n        class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\"\n        aria-hidden=\"true\"\n      >\n        <polyline points=\"6 9 12 15 18 9\" />\n      </svg>\n    </summary>\n    \"\"\"\n  end\n\n  attr :class, :string, default: nil\n  slot :inner_block, required: true\n\n  def exclusive_accordion_content(assigns) do\n    ~H\"\"\"\n    <div data-slot=\"exclusive-accordion-content\" class={[\"overflow-hidden pt-0 pb-4 text-sm\", @class]}>\n      {render_slot(@inner_block)}\n    </div>\n    \"\"\"\n  end\nend\n"
    },
    {
      "path": "registry/html/exclusive-accordion.html",
      "type": "registry:file",
      "target": "snippets/exclusive-accordion.html",
      "content": "<!--\n  shadcn-htmx — raw HTML exclusive-accordion snippet.\n  Mirrors registry/ui/exclusive-accordion.tsx EXACTLY.\n\n  The scriptless single-open accordion: every <details> shares one `name`\n  attribute, so the browser keeps exactly one open at a time — opening one\n  auto-closes the others. NO JavaScript, no boot script. Relies only on theme\n  tokens. Per the HTML spec, if multiple items carry `open`, only the first in\n  source order renders open.\n\n  Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details#name\n\n  Distinct accordions on one page must use distinct `name` values, or opening\n  an item in one closes an item in the other.\n-->\n\n<div data-slot=\"exclusive-accordion\" data-name=\"faq\" class=\"w-full\">\n\n  <details name=\"faq\" data-slot=\"exclusive-accordion-item\" data-value=\"q1\" open class=\"border-b last:border-b-0\">\n    <summary data-slot=\"exclusive-accordion-trigger\"\n      class=\"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 list-none [&::-webkit-details-marker]:hidden [details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\">\n      What's htmx?\n      <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n           data-slot=\"exclusive-accordion-chevron\" class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\" aria-hidden=\"true\">\n        <polyline points=\"6 9 12 15 18 9\" />\n      </svg>\n    </summary>\n    <div data-slot=\"exclusive-accordion-content\" class=\"overflow-hidden pt-0 pb-4 text-sm\">\n      A small library that turns any HTML attribute into an AJAX trigger — no JSON, no client framework needed.\n    </div>\n  </details>\n\n  <details name=\"faq\" data-slot=\"exclusive-accordion-item\" data-value=\"q2\" class=\"border-b last:border-b-0\">\n    <summary data-slot=\"exclusive-accordion-trigger\"\n      class=\"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 list-none [&::-webkit-details-marker]:hidden [details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\">\n      Why pair it with Tailwind v4?\n      <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n           data-slot=\"exclusive-accordion-chevron\" class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\" aria-hidden=\"true\">\n        <polyline points=\"6 9 12 15 18 9\" />\n      </svg>\n    </summary>\n    <div data-slot=\"exclusive-accordion-content\" class=\"overflow-hidden pt-0 pb-4 text-sm\">\n      Utility-first CSS keeps the markup self-explanatory and the bundle small.\n    </div>\n  </details>\n\n  <details name=\"faq\" data-slot=\"exclusive-accordion-item\" data-value=\"q3\" class=\"border-b last:border-b-0\">\n    <summary data-slot=\"exclusive-accordion-trigger\"\n      class=\"flex cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none select-none marker:hidden hover:underline focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 list-none [&::-webkit-details-marker]:hidden [details[open]>&_[data-slot=exclusive-accordion-chevron]]:rotate-180\">\n      Does it work without JavaScript?\n      <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\n           data-slot=\"exclusive-accordion-chevron\" class=\"pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200\" aria-hidden=\"true\">\n        <polyline points=\"6 9 12 15 18 9\" />\n      </svg>\n    </summary>\n    <div data-slot=\"exclusive-accordion-content\" class=\"overflow-hidden pt-0 pb-4 text-sm\">\n      Yes — the exclusivity is the native <code class=\"rounded bg-muted px-1 py-0.5\">&lt;details name&gt;</code> grouping. Zero script required.\n    </div>\n  </details>\n</div>\n"
    }
  ]
}
