# `PhiaUi.Components.Accordion`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/layout/accordion.ex#L1)

Accordion component using exclusively `Phoenix.LiveView.JS` — no JS hooks required.

An accordion presents a list of items where each item can expand to reveal
its content. This implementation is zero-JavaScript-bundle: all toggle
logic is expressed as `Phoenix.LiveView.JS` commands compiled into HTML
`phx-click` attributes, so transitions execute without a server round-trip.

## Interaction Modes

| Mode         | Behaviour                                                   |
|--------------|-------------------------------------------------------------|
| `:single`    | Only one item can be open at a time. Opening a new item     |
|              | automatically closes the previously open one.              |
| `:multiple`  | Any number of items can be open simultaneously.            |

## Sub-components

| Function              | Element  | Purpose                                       |
|-----------------------|----------|-----------------------------------------------|
| `accordion/1`         | `div`    | Root container                                |
| `accordion_item/1`    | `div`    | Per-item wrapper with border and spacing      |
| `accordion_trigger/1` | `button` | Toggle button with animated chevron + ARIA    |
| `accordion_content/1` | `div`    | Collapsible content panel                     |

## Example — FAQ (single mode)

The most common use case: a list of questions where only one answer is
visible at a time, reducing cognitive load.

    <.accordion id="faq" type={:single}>
      <.accordion_item value="q1" type={:single} accordion_id="faq">
        <.accordion_trigger value="q1" type={:single} accordion_id="faq">
          What is PhiaUI?
        </.accordion_trigger>
        <.accordion_content value="q1">
          A Phoenix LiveView UI component library inspired by shadcn/ui.
        </.accordion_content>
      </.accordion_item>

      <.accordion_item value="q2" type={:single} accordion_id="faq">
        <.accordion_trigger value="q2" type={:single} accordion_id="faq">
          Do I need to install any JavaScript packages?
        </.accordion_trigger>
        <.accordion_content value="q2">
          No. The accordion uses only Phoenix.LiveView.JS for all interactions.
        </.accordion_content>
      </.accordion_item>
    </.accordion>

## Example — Settings Panel (multiple mode)

Use `:multiple` when independent sections can all be open at once, such as
a settings page with distinct categories.

    <.accordion id="settings" type={:multiple}>
      <.accordion_item value="profile" type={:multiple} accordion_id="settings">
        <.accordion_trigger value="profile" type={:multiple} accordion_id="settings">
          Profile Settings
        </.accordion_trigger>
        <.accordion_content value="profile">
          <.input name="name" label="Display Name" value={@user.name} />
        </.accordion_content>
      </.accordion_item>

      <.accordion_item value="notifications" type={:multiple} accordion_id="settings">
        <.accordion_trigger value="notifications" type={:multiple} accordion_id="settings">
          Notification Preferences
        </.accordion_trigger>
        <.accordion_content value="notifications">
          <.checkbox name="email_notifs" label="Email notifications" />
        </.accordion_content>
      </.accordion_item>
    </.accordion>

## Opening an Item by Default

Pass `open={true}` to both the trigger and the content to render a specific
item expanded on first load. This is the recommended way to implement
`default_value` behaviour:

    <%# Open the item whose value matches the initial default %>
    <.accordion_trigger value="q1" ... open={"q1" == @default_open}>
    <.accordion_content value="q1" ... open={"q1" == @default_open}>

## Collapsible Single Mode

By default in `:single` mode, clicking the currently open item does nothing
(the item stays open). Pass `collapsible={true}` to the trigger to allow
re-clicking an open item to close it:

    <.accordion_trigger value="q1" type={:single} accordion_id="faq" collapsible={true}>

## Disabled Items

Prevent interaction on specific items using the `:disabled` attribute on
`accordion_item/1`. The item renders with `opacity-50` and `pointer-events-none`:

    <.accordion_item value="premium" type={:single} accordion_id="faq" disabled={!@user.premium}>

## Accessibility

- Trigger buttons use `aria-expanded` (toggled via `JS.set_attribute`) and
  `aria-controls` pointing at the content panel ID
- Content panels use stable IDs (`accordion-content-{value}`) referenced by
  `aria-controls`
- The chevron icon carries `aria-hidden="true"` so screen readers ignore it
- Disabled items get `aria-disabled="true"` on the wrapper div

# `accordion`

Renders the accordion root container.

The `id` is the coordination point for `:single` mode — all child triggers
reference it to close sibling items when a new one is opened.

## Attributes

* `id` (`:string`) - Unique ID for the root container. **Required for `:single` mode** — the
  `accordion_trigger/1` uses this ID to target all sibling items via CSS
  selectors like `#faq [data-accordion-content]` when closing others.

  Defaults to `nil`.
* `type` (`:atom`) - Interaction mode: `:single` allows one open item, `:multiple` allows many. Defaults to `:single`. Must be one of `:single`, or `:multiple`.
* `class` (`:string`) - Additional CSS classes. Defaults to `nil`.
* Global attributes are accepted. Extra HTML attributes forwarded to the root `<div>`.
## Slots

* `inner_block` (required) - `accordion_item/1` sub-components.

# `accordion_content`

Renders the collapsible accordion content panel.

The panel ID (`accordion-content-{value}`) is the coordination point:
- `accordion_trigger/1` references it via `aria-controls`
- The JS toggle commands target it by ID

By default the panel starts hidden (`display: none`). The inner `pb-4 pt-0`
wrapper provides consistent padding without affecting the transition.

## Default Open

To render an item expanded on initial page load, pass `open={true}` to both
the trigger and its corresponding content:

    <.accordion_trigger value="welcome" ... open={@default_open == "welcome"}>
      Welcome
    </.accordion_trigger>
    <.accordion_content value="welcome" open={@default_open == "welcome"}>
      Content here.
    </.accordion_content>

## Attributes

* `value` (`:string`) (required) - Must match the `:value` of the parent `accordion_item/1`.
* `open` (`:boolean`) - When `true`, the content starts visible (rendered with `display: block`).
  Pair with `open={true}` on the corresponding `accordion_trigger/1` to
  render an item expanded on first load.

  Defaults to `false`.
* `class` (`:string`) - Additional CSS classes. Defaults to `nil`.
* Global attributes are accepted. Extra HTML attributes forwarded to the content `<div>`.
## Slots

* `inner_block` (required) - Content shown when the item is expanded.

# `accordion_item`

Renders an accordion item wrapper.

Each item has a bottom border by default to visually separate it from its
neighbours. The border is part of the item — not the root container — so
there is no double-border at the top of the first item.

## Attributes

* `value` (`:string`) (required) - Unique string identifier for this item within the accordion. Used to build
  stable DOM IDs: `accordion-trigger-{value}` and `accordion-content-{value}`.
  Must be unique across all items in the same accordion instance.

* `type` (`:atom`) - Inherited from the parent `accordion/1` — controls toggle behaviour. Defaults to `:single`. Must be one of `:single`, or `:multiple`.
* `accordion_id` (`:string`) - ID of the parent `accordion/1` — required for `:single` exclusivity. Defaults to `nil`.
* `disabled` (`:boolean`) - When `true`, prevents interaction with this item. Applies `pointer-events-none`
  and `opacity-50` via CSS, and sets `aria-disabled="true"` for screen readers.
  Use this to indicate that a feature is unavailable (e.g. behind a paywall).

  Defaults to `false`.
* `class` (`:string`) - Additional CSS classes. Defaults to `nil`.
* Global attributes are accepted. Extra HTML attributes forwarded to the wrapper `<div>`.
## Slots

* `inner_block` (required) - `accordion_trigger/1` and `accordion_content/1` sub-components.

# `accordion_trigger`

Renders the accordion trigger button with `Phoenix.LiveView.JS`-powered toggle.

The toggle JS command is computed at render time by `build_toggle_js/4` and
embedded into the `phx-click` attribute. This means the client executes the
animation directly without a server round-trip.

The animated chevron rotates 180° when the item is open. It is driven by
the `rotate-180` Tailwind class toggled by the JS command, and uses
`transition-transform` for a smooth animation.

## ARIA attributes

- `aria-expanded` — reflects current open state; updated by the JS command
- `aria-controls` — points to the `accordion-content-{value}` panel ID so
  screen readers can announce "controls this region"

## Attributes

* `value` (`:string`) (required) - Must match the `:value` of the parent `accordion_item/1`.
* `type` (`:atom`) - Inherited from the parent `accordion/1` — controls the JS toggle strategy. Defaults to `:single`. Must be one of `:single`, or `:multiple`.
* `accordion_id` (`:string`) - ID of the parent `accordion/1` — required for `:single` mode to close siblings. Defaults to `nil`.
* `collapsible` (`:boolean`) - When `true` in `:single` mode, clicking the currently open item closes it.
  When `false` (default), the open item cannot be closed by clicking its trigger —
  exactly one item is always open once any item has been opened.
  Only effective in `:single` mode with `accordion_id` set.

  Defaults to `false`.
* `open` (`:boolean`) - When `true`, the item starts in the expanded state. This controls the
  initial `aria-expanded` attribute and the chevron rotation. Pair with
  `open={true}` on the corresponding `accordion_content/1`.

  Defaults to `false`.
* `class` (`:string`) - Additional CSS classes. Defaults to `nil`.
* Global attributes are accepted. Extra HTML attributes forwarded to the `<button>`.
## Slots

* `inner_block` (required) - Trigger label — question text, section name, etc.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
