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

Expandable table rows with collapsible detail panels.

Pairs two components: `expandable_table_row/1` adds a chevron toggle in the
first cell, and `expandable_table_detail/1` renders the collapsible detail
row below it. All expand/collapse state lives in the LiveView.

## Sub-components

| Function                   | HTML element | Purpose                                |
|----------------------------|--------------|----------------------------------------|
| `expandable_table_row/1`   | `<tr>`       | Row with expand/collapse chevron cell  |
| `expandable_table_detail/1`| `<tr>`       | Hidden detail row shown when expanded  |

## Example

    defmodule MyAppWeb.OrdersLive do
      use MyAppWeb, :live_view

      def mount(_params, _session, socket) do
        {:ok, assign(socket, expanded_rows: MapSet.new(), orders: Orders.list())}
      end

      def handle_event("toggle_row", %{"id" => id}, socket) do
        expanded =
          if MapSet.member?(socket.assigns.expanded_rows, id),
            do: MapSet.delete(socket.assigns.expanded_rows, id),
            else: MapSet.put(socket.assigns.expanded_rows, id)

        {:noreply, assign(socket, expanded_rows: expanded)}
      end

      def render(assigns) do
        ~H"""
        <.table>
          <.table_body>
            <%= for order <- @orders do %>
              <.expandable_table_row
                row_id={to_string(order.id)}
                expanded={order.id in @expanded_rows}
                on_toggle="toggle_row"
              >
                <.table_cell>{order.number}</.table_cell>
                <.table_cell>{order.customer}</.table_cell>
                <.table_cell>{order.total}</.table_cell>
              </.expandable_table_row>
              <.expandable_table_detail
                row_id={to_string(order.id)}
                expanded={order.id in @expanded_rows}
              >
                <p class="text-sm text-muted-foreground">Order details for {order.number}</p>
              </.expandable_table_detail>
            <% end %>
          </.table_body>
        </.table>
        """
      end
    end

## Accessibility

- The chevron `<button>` has `aria-expanded` set to `"true"` or `"false"`
- `aria-controls` links the button to the detail row ID (`row-detail-{row_id}`)
- The detail `<tr>` has a matching `id` for the `aria-controls` reference

# `expandable_table_detail`

Renders a collapsible detail row below its paired `expandable_table_row/1`.

When `expanded={false}` the `hidden` class hides the row entirely. When
`expanded={true}` the row is visible. The `id` matches the `aria-controls`
reference in the toggle button.

## Example

    <.expandable_table_detail
      row_id={to_string(order.id)}
      expanded={order.id in @expanded_rows}
    >
      <div class="rounded-md bg-muted/30 p-4 text-sm">
        <p>Items: {length(order.items)}</p>
        <p>Shipping: {order.shipping_address}</p>
      </div>
    </.expandable_table_detail>

## Attributes

* `row_id` (`:string`) (required) - Must match the `row_id` of the paired `expandable_table_row/1`. Used to
  build the `id` attribute that `aria-controls` references.

* `expanded` (`:boolean`) - When `false` (default) the row is hidden via `hidden` class. Controlled by LiveView. Defaults to `false`.
* `col_span` (`:integer`) - Number of columns this detail row spans. Default 100 spans all columns. Defaults to `100`.
* `class` (`:string`) - Additional CSS classes for the `<tr>`. Defaults to `nil`.
## Slots

* `inner_block` (required) - Detail content — can be a nested table, description list, JSON viewer, etc.

# `expandable_table_row`

Renders a `<tr>` with an expand/collapse chevron prepended in the first cell.

The chevron rotates 90° when `expanded={true}` via a Tailwind transition.
All interaction state lives in the parent LiveView — this component is
stateless.

Pair with `expandable_table_detail/1` using the same `row_id`.

## Example

    <.expandable_table_row
      row_id={to_string(order.id)}
      expanded={order.id in @expanded_rows}
      on_toggle="toggle_row"
    >
      <.table_cell>{order.number}</.table_cell>
      <.table_cell>{order.total}</.table_cell>
    </.expandable_table_row>

## Attributes

* `expanded` (`:boolean`) - Whether the detail row is currently visible. Controls chevron rotation. Defaults to `false`.
* `on_toggle` (`:string`) - `phx-click` event fired when the expand/collapse button is clicked.
  Receives `phx-value-id` set to `row_id`. Toggle membership in your
  `expanded_rows` set in the handler.

  Defaults to `"toggle_row"`.
* `row_id` (`:string`) (required) - Stable identifier for this row. Used for `phx-value-id` and to build the
  `aria-controls` / `id` pair with the matching `expandable_table_detail/1`.

* `class` (`:string`) - Additional CSS classes for the `<tr>`. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the `<tr>` element (e.g. `id`).
## Slots

* `inner_block` (required) - Table data cells (`table_cell/1` or `<td>`) for this row, **excluding**
  the expand toggle cell — that is prepended automatically.

---

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