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

A table with a search box, sortable headers, a pagination footer and row selection, in the
two looks LineOne shows: `advanced` (the Table Advanced page: a title bar with a search
that slides open, the table as a card, "Show 10 entries" and a pager underneath) and `grid`
(the Grid Table page: a search box on the right, sort arrows, "Showing 1 to 10 of 15
results" and Previous/Next).

The LiveView owns the state: it filters, sorts and slices the rows and gives the component
the current page; the component only renders it and sends events back.

    <.data_table
      id="users"
      rows={@users}
      search={@search}
      on_search="search"
      sort_by={@sort_by}
      sort_dir={@sort_dir}
      on_sort="sort"
      page={@page}
      page_size={10}
      total={@total}
      on_page="paginate"
    >
      <:title>Users Table</:title>
      <:col :let={user} label="Name" sort_key="name">{user.name}</:col>
      <:col :let={user} label="Email">{user.email}</:col>
    </.data_table>

    def handle_event("search", %{"search" => q}, socket), do: ...
    def handle_event("sort", %{"column" => col, "direction" => dir}, socket), do: ...
    def handle_event("paginate", %{"page" => page}, socket), do: ...

Rows may be a stream (`rows={@streams.users}`); the body then renders with
`phx-update="stream"` and `total` drives the footer. `:col`, `:action`, `:expand`,
`:empty`, `row_id`, `row_key`, `row_item`, `row_click` and selection work as in
`LineaUI.Components.Table.table/1`.

# `data_table`

Renders a data table. The LiveView passes the rows of the current page and handles the
events below.

    <.data_table
      id="contacts"
      variant="grid"
      rows={@rows}
      total={@total}
      page={@page}
      on_page="paginate"
      search={@search}
      on_search="search"
      sort_by={@sort_by}
      sort_dir={@sort_dir}
      on_sort="sort"
      row_key={& &1.id}
      selected={@selected}
      on_select="select"
      on_select_all="select_all"
    >
      <:col :let={c} label="Name" sort_key="name">{c.name}</:col>
      <:col :let={c} label="Email" sort_key="email">{c.email}</:col>
    </.data_table>

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

* `on_search` — the search input changed or was submitted: `%{"search" => query}`.
* `on_sort` — a sortable header was clicked: `%{"column" => sort_key, "direction" => "asc" | "desc"}`,
  the direction to sort by next.
* `on_page` — a page was chosen: `%{"page" => "3"}` (a string, as every `phx-value-*`).
  With `page_path` (a function of the page number) the pager renders `patch` links instead.
* `on_page_size` — the "Show N entries" select changed: `%{"page_size" => "30"}`.
* `on_select` — a row checkbox: `%{"id" => key, "selected" => "true" | "false"}`.
* `on_select_all` — the header checkbox: `%{"selected" => "true" | "false"}`.

The footer shows when `on_page` or `page_path` is given (unless `footer={false}`); the search
when `on_search` is.

## Attributes

* `id` (`:string`) (required)
* `rows` (`:any`) (required) - The rows of the current page, a list or a stream.
* `variant` (`:string`) - Defaults to `"advanced"`. Must be one of `"advanced"`, or `"grid"`.
* `row_id` (`:any`) - A function giving each row's DOM id; streams default to the stream id. Defaults to `nil`.
* `row_key` (`:any`) - A function giving a row's selection key; defaults to its DOM id. Defaults to `nil`.
* `row_item` (`:any`) - Maps each row before the slots get it. Defaults to `&Function.identity/1`.
* `row_click` (`:any`) - A function of the row returning a `JS` or an event name. Defaults to `nil`.
* `hoverable` (`:boolean`) - Highlights the hovered row; on by default, off for expandable rows. Defaults to `nil`.
* `search` (`:string`) - The current query. Defaults to `""`.
* `search_placeholder` (`:string`) - Placeholder of the search input. Defaults to `nil`.
* `on_search` (`:any`) - See the events above. Defaults to `nil`.
* `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`) - See the events above. Defaults to `nil`.
* `page` (`:integer`) - The current page, from 1. Defaults to `1`.
* `page_size` (`:integer`) - Rows per page. Defaults to `10`.
* `total` (`:integer`) - Rows across every page. Defaults to the row count. Defaults to `nil`.
* `on_page` (`:any`) - See the events above. Defaults to `nil`.
* `page_path` (`:any`) - A function of the page number returning a path. Defaults to `nil`.
* `footer` (`:boolean`) - `false` leaves out the footer (pager, summary and page-size select) even when `on_page` is given, for a table with only a search. Defaults to `true`.
* `compact` (`:boolean`) - Tighter cells, see `table/1`. Defaults to `false`.
* `headless` (`:boolean`) - No `<thead>`, see `table/1`. Defaults to `false`.
* `borderless` (`:boolean`) - No row rules, see `table/1`. Defaults to `false`.
* `page_sizes` (`:list`) - Options of the "Show N entries" select. Defaults to `[]`.
* `on_page_size` (`:any`) - See the events above. Defaults to `nil`.
* `pager` (`:string`) - The pager look of the `advanced` variant. Defaults to `"rounded"`. Must be one of `"rounded"`, `"pill"`, or `"circle"`.
* `show_label` (`:string`) - Text before the page-size select. Defaults to `"Show"`.
* `entries_label` (`:string`) - Text after the page-size select. Defaults to `"entries"`.
* `prev_label` (`:string`) - Text of the `grid` pager's first button. Defaults to `"Previous"`.
* `next_label` (`:string`) - Text of the `grid` pager's last button. Defaults to `"Next"`.
* `selected` (`:list`) - Keys of the selected rows. Defaults to `[]`.
* `all_selected` (`:boolean`) - Whether the header checkbox is checked; computed for lists. Defaults to `nil`.
* `on_select` (`:any`) - See the events above. Defaults to `nil`.
* `on_select_all` (`:any`) - See the events above. Defaults to `nil`.
* `expand_label` (`:string`) - Header of the expand column. Defaults to `nil`.
* `target` (`:any`) - `phx-target` of every event. 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`.
* `title` - The `advanced` variant's heading.
* `actions` - Buttons at the right of the `advanced` title bar.
* `filters` - A filter panel the `advanced` title bar's filter button opens. Receives the `JS` that toggles it.
* `summary` - Replaces the "1 - 10 of 15 entries" text; receives `%{first: n, last: n, total: n}`.
* `action` - Cells appended to every row.
* `expand` - Detail under each row, see `LineaUI.Components.Table.table/1`.
* `empty` - Shown when `rows` is an empty list.

# `data_table_toggle_filters`

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

The `JS` that opens and closes the filter panel of the data table with `id` (the `:filters`
slot also receives it).

    <.button phx-click={data_table_toggle_filters("projects")}>Filters</.button>

# `table_search`

LineOne's collapsing search: a magnifier button that slides a borderless input open, as in the
title bar of the Table Advanced page. `data_table/1` uses it, and it works on its own next to
any title.

    <div class="flex items-center justify-between">
      <h2>Users</h2>
      <.table_search id="users" value={@search} on_search="search" />
    </div>

Events: `on_search` (an event name or `%JS{}`, sent to `target` when given) receives
`%{"search" => query}` on every change (debounced 300ms) and on submit. The input has the
DOM id `#{id}-search` and the form `#{id}-search-form`. The input starts open when `value`
is not empty.

## Attributes

* `id` (`:string`) (required)
* `value` (`:string`) - The current query. Defaults to `""`.
* `on_search` (`:any`) - Event name or `%JS{}` for the query changes. Defaults to `nil`.
* `target` (`:any`) - `phx-target` of `on_search`. Defaults to `nil`.
* `placeholder` (`:string`) - Placeholder and label; "Search here..." by default. Defaults to `nil`.
* `class` (`:any`) - Defaults to `nil`.
* Global attributes are accepted.

---

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