AvenUI.Components.DataTable (AvenUI v1.0.0)

Copy Markdown View Source

Rich data table with filter bar, server-side sort, and pagination.

All filtering and sorting fires server-side phx events — the developer queries the database and updates the rows assign. This scales to any dataset size and integrates cleanly with Ecto.

Use AvenUI.DataTable struct to manage state in your LiveView.

Basic example

<%!-- In the template --%>
<.data_table
  id="users-table"
  rows={@rows}
  table={@table}
  on_filter="dt_filter"
  on_sort="dt_sort"
  on_paginate="dt_paginate"
>
  <:filter>
    <.dt_search name="search" placeholder="Search users…" />
    <.dt_select name="status" prompt="All statuses"
      options={[{"Active", "active"}, {"Inactive", "inactive"}]} />
  </:filter>

  <:col :let={user} label="Name" field="name" sortable>
    <div class="flex items-center gap-2">
      <.avatar initials={String.first(user.name)} size="sm" />
      <span class="font-medium"><%= user.name %></span>
    </div>
  </:col>
  <:col :let={user} label="Email" field="email" sortable>
    <%= user.email %>
  </:col>
  <:col :let={user} label="Status">
    <.badge variant={if user.active, do: "success", else: "default"}>
      <%= if user.active, do: "Active", else: "Inactive" %>
    </.badge>
  </:col>
  <:col :let={user} label="Joined" field="inserted_at" sortable>
    <%= Calendar.strftime(user.inserted_at, "%b %d, %Y") %>
  </:col>

  <:action :let={user}>
    <.button size="xs" variant="ghost" phx-click="edit" phx-value-id={user.id}>
      Edit
    </.button>
    <.button size="xs" variant="ghost" phx-click="delete" phx-value-id={user.id}>
      Delete
    </.button>
  </:action>
</.data_table>

Required LiveView handlers

alias AvenUI.DataTable

def mount(_, _, socket) do
  {:ok,
   socket
   |> assign(:table, DataTable.new(per_page: 20))
   |> load_rows()}
end

def handle_event("dt_filter", params, socket) do
  table = socket.assigns.table
          |> DataTable.set_filter(params)
          |> DataTable.reset_page()
  {:noreply, socket |> assign(:table, table) |> load_rows()}
end

def handle_event("dt_sort", %{"field" => field}, socket) do
  table = DataTable.toggle_sort(socket.assigns.table, field)
  {:noreply, socket |> assign(:table, table) |> load_rows()}
end

def handle_event("dt_paginate", %{"page" => page}, socket) do
  table = DataTable.set_page(socket.assigns.table, String.to_integer(page))
  {:noreply, socket |> assign(:table, table) |> load_rows()}
end

defp load_rows(socket) do
  dt = socket.assigns.table
  {rows, total} = MyApp.Accounts.list_users(
    search:     DataTable.filter_value(dt, "search"),
    status:     DataTable.filter_value(dt, "status"),
    sort_field: dt.sort_field,
    sort_dir:   dt.sort_dir,
    limit:      dt.per_page,
    offset:     DataTable.offset(dt)
  )
  socket
  |> assign(:rows, rows)
  |> assign(:table, DataTable.put_total(dt, total))
end

Summary

Functions

Rich data table with filter bar, sort, and pagination.

Search input for use inside the data_table :filter slot.

Select dropdown for use inside the data_table :filter slot.

Functions

data_table(assigns)

Rich data table with filter bar, sort, and pagination.

Attributes

  • id (:string) (required)
  • rows (:list) (required)
  • table (:any) (required) - AvenUI.DataTable struct.
  • on_filter (:string) - phx event for filter changes. Defaults to "dt_filter".
  • on_sort (:string) - phx event for sort changes. Defaults to "dt_sort".
  • on_paginate (:string) - phx event for page changes. Defaults to "dt_paginate".
  • title (:string) - Defaults to nil.
  • subtitle (:string) - Defaults to nil.
  • striped (:boolean) - Defaults to false.
  • class (:string) - Defaults to nil.

Slots

  • filter - Filter bar content — use dt_search and dt_select inside.
  • toolbar - Right side of the toolbar — buttons, export, etc.
  • col (required) - Accepts attributes:
    • label (:string)
    • field (:string) - Field name — required for sortable columns.
    • sortable (:boolean)
    • class (:string)
    • align (:string) - Must be one of "left", "center", or "right".
  • action - Action buttons — revealed on row hover.
  • empty - Content shown when rows is empty.

dt_search(assigns)

Search input for use inside the data_table :filter slot.

Attributes

  • name (:string) (required)
  • placeholder (:string) - Defaults to "Search…".
  • value (:string) - Defaults to "".
  • class (:string) - Defaults to nil.

dt_select(assigns)

Select dropdown for use inside the data_table :filter slot.

Attributes

  • name (:string) (required)
  • options (:list) (required) - List of {label, value} tuples.
  • prompt (:string) - Defaults to "All".
  • value (:string) - Defaults to "".
  • class (:string) - Defaults to nil.