# `LineaUI.Components.Table`
[🔗](https://github.com/devaction-labs/linea_ui/blob/v0.1.1/lib/linea_ui/components/table.ex#L1)

LineOne's tables: basic, bordered, hoverable, zebra and the grid look, with `:col` slots
the way Phoenix's generated `CoreComponents.table/1` takes them.

    <.table id="users" rows={@users}>
      <:col :let={user} label="Name">{user.name}</:col>
      <:col :let={user} label="Job">{user.job}</:col>
    </.table>

    <.table id="users" rows={@streams.users} variant="hoverable" row_click={&JS.navigate(~p"/users/#{elem(&1, 1)}")}>
      <:col :let={{_id, user}} label="Name">{user.name}</:col>
      <:action :let={{_id, user}}><.button size="xs">Edit</.button></:action>
    </.table>

`variant="hoverable"` and `"zebra"` draw the filled header; `rounded` picks its corners:
`row` rounds both ends of the header row (a table inside a padded card), `top` only the
top corners (a table that is the top of a card) and `none` keeps it square (full width).

Sortable headers: give a column `sort_key` and the table `on_sort`; the header becomes a
button that sends `on_sort` with `%{"column" => sort_key, "direction" => "asc" | "desc"}`,
the direction being the one to sort by next. `sort_by` and `sort_dir` mark the current order.

    <.table id="t" rows={@rows} on_sort="sort" sort_by={@sort_by} sort_dir={@sort_dir}>
      <:col :let={row} label="Name" sort_key="name">{row.name}</:col>
    </.table>

Row selection: `on_select` adds a checkbox column. Each checkbox sends `on_select` with
`%{"id" => key, "selected" => "true" | "false"}` (the new state of that row); the header one
sends `on_select_all` with `%{"selected" => "true" | "false"}`. `selected` is the list of keys
checked. The key is `row_key.(row)`, or the row's DOM id when `row_key` is not given; keys
are compared as given, so pass strings or convert the `"id"` back.

Density and chrome: `compact` tightens the cell padding, `borderless` drops the row rules (and
the cell borders of `bordered`), `headless` leaves out the `<thead>` altogether. A column's
`align` (`left`, `center`, `right`) aligns its header and cells.

    <.table id="stats" rows={@rows} compact borderless headless>
      <:col :let={row}>{row.label}</:col>
      <:col :let={row} align="right">{row.count}</:col>
    </.table>

Every event attr takes an event name or a `%JS{}`; `target` sets `phx-target`.

Expandable rows: an `:expand` slot adds a last column with a chevron that shows a detail
row under each row (`expand_label` names that column). The slot receives
`%{row: row, toggle: js}`, `toggle` being the `JS` that opens and closes it. Expandable
rows render one `<tbody>` per row, so they take a list, not a stream.

# `table`

Renders a table of `rows` (a list or a stream), one column per `:col` slot.

    <.table id="people" rows={@streams.people} variant="zebra">
      <:col :let={{_id, person}} label="Name">{person.name}</:col>
      <:col :let={{_id, person}} label="Job">{person.job}</:col>
      <:action :let={{_id, person}}>
        <.button size="xs" phx-click="edit" phx-value-id={person.id}>Edit</.button>
      </:action>
    </.table>

Events (each an event name or a `%JS{}`, sent to `target` when given):

* `on_sort` — a sortable header was clicked:
  `%{"column" => sort_key, "direction" => "asc" | "desc"}` (the direction to sort by next).
* `on_select` — a row checkbox: `%{"id" => key, "selected" => "true" | "false"}`.
* `on_select_all` — the header checkbox: `%{"selected" => "true" | "false"}`.

With a stream, `selected` only reaches the rows the server re-renders: `stream_insert` the
rows whose selection changed, and give `all_selected` for the header checkbox.

## Attributes

* `id` (`:string`) (required)
* `rows` (`:any`) (required) - A list or a `@streams.x` stream.
* `row_id` (`:any`) - A function giving each row's DOM id. Streams default to the stream id. Defaults to `nil`.
* `row_click` (`:any`) - A function of the row returning a `JS` or an event. Defaults to `nil`.
* `row_item` (`:any`) - Maps each row before it is given to the slots. Defaults to `&Function.identity/1`.
* `row_key` (`:any`) - A function giving the selection key of a row. Defaults to the row's DOM id. Defaults to `nil`.
* `variant` (`:string`) - `grid` is the gridjs look of LineOne's Grid Table page. Defaults to `"basic"`. Must be one of `"basic"`, `"bordered"`, `"hoverable"`, `"zebra"`, or `"grid"`.
* `rounded` (`:string`) - Corners of the filled header of `hoverable` and `zebra`. Defaults to `"row"`. Must be one of `"row"`, `"top"`, or `"none"`.
* `sort_by` (`:string`) - The `sort_key` of the sorted column. Defaults to `nil`.
* `sort_dir` (`:string`) - Direction of `sort_by`. Defaults to `"asc"`. Must be one of `"asc"`, or `"desc"`.
* `on_sort` (`:any`) - Event sent when a sortable header is clicked. Defaults to `nil`.
* `on_select` (`:any`) - Event sent when a row checkbox is clicked. Defaults to `nil`.
* `on_select_all` (`:any`) - Event sent by the header checkbox. Defaults to `nil`.
* `selected` (`:list`) - The keys of the selected rows. Defaults to `[]`.
* `all_selected` (`:boolean`) - Whether the header checkbox is checked. Computed for lists; give it for streams. Defaults to `nil`.
* `hoverable` (`:boolean`) - Highlights the hovered row. Defaults to the variant's own behavior. Defaults to `nil`.
* `compact` (`:boolean`) - Tighter cells: `px-3 py-2` instead of the variant's padding. Defaults to `false`.
* `headless` (`:boolean`) - Renders no `<thead>` at all (not hidden columns), for list-like tables. Defaults to `false`.
* `borderless` (`:boolean`) - Removes the rules between rows, and the cell borders of the `bordered` variant. Defaults to `false`.
* `target` (`:any`) - `phx-target` of the events. Defaults to `nil`.
* `expand_label` (`:string`) - Header of the expand column. Defaults to `nil`.
* `wrapper_class` (`:any`) - Classes of the scrolling wrapper. Defaults to `nil`.
* `class` (`:any`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `col` (required) - A column; receives the row (after `row_item`). Accepts attributes:

  * `label` (`:string`) - Header text.
  * `class` (`:any`) - Extra classes of the column's cells (the header takes `head_class`).
  * `head_class` (`:any`) - Extra classes of the column's header.
  * `align` (`:string`) - Text alignment of the column's header and cells. Must be one of `"left"`, `"center"`, or `"right"`.
  * `sort_key` (`:string`) - Makes the header sortable; sent as `"column"` in `on_sort`.
* `action` - Cells appended to every row, after the columns.
* `expand` - Detail shown under a row; receives `%{row: row, toggle: js}`.
* `empty` - Shown in a full-width row when `rows` is an empty list.

# `table_toggle_row`

```elixir
@spec table_toggle_row(Phoenix.LiveView.JS.t(), String.t()) :: Phoenix.LiveView.JS.t()
```

The `JS` that shows or hides the detail panel of the expandable row with DOM id `row_id`
(the `toggle` the `:expand` slot receives is this, already bound to its row).

    <.button phx-click={table_toggle_row("devs-row-0")}>Details</.button>

---

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