Shadix.Components.DataTable (shadix v0.0.1)

Copy Markdown View Source

A styling and sorting recipe layered over Shadix.Components.Table.

The shadcn "Data Table" example is not a standalone component: it is a guide for wiring TanStack Table (column defs, sorting, filtering, pagination, row selection, visibility) into the presentational Table primitives. This v1 is deliberately not a TanStack port. It is a thin set of helpers that render the chrome — a bordered container, sortable column-header buttons, and an optional pagination bar — on top of the existing Table components.

Scope and simplifications

  • The consumer owns the data and all state. Your LiveView holds the rows, the current sort field/direction, and the current page; it does the actual sorting and slicing. These helpers only render the surface. There is no LiveView hook and no client-side state.
  • You build the table yourself. data_table/1 is just a bordered wrapper: put a <Shadix.Components.Table.table> (with its own header/body) inside it. The recipe does not generate rows from column definitions.
  • Sorting is "controlled". data_table_column_header/1 renders a button that shows the current sort direction for that column (via :sort, one of "asc", "desc", or nil) and runs the :on_sort JS you pass. Your handler decides the next state and re-renders with an updated :sort.
  • Pagination is "controlled". data_table_pagination/1 renders prev/next buttons and a "Page X of Y" label. It enforces nothing; your :on_prev / :on_next handlers update the page and you pass :page / :total_pages back in. Buttons can be disabled via :prev_disabled / :next_disabled.

data-slots

  • data-table — the bordered container <div>.
  • data-table-column-header — the sortable header <button>.
  • data-table-pagination — the pagination bar <div> (a labelled navigation landmark).

Accessibility

The sortable header is a plain <button> and intentionally does not carry aria-sort — that attribute is not allowed on <button>; it belongs on the columnheader (the <th>). If you want to expose the sort state to assistive technology via aria-sort, set it on the consuming <Shadix.Components.Table.table_head> (e.g. aria-sort="ascending"). The button instead conveys the sort control through an aria-label.

Example

<Shadix.Components.DataTable.data_table>
  <Shadix.Components.Table.table>
    <Shadix.Components.Table.table_header>
      <Shadix.Components.Table.table_row>
        <Shadix.Components.Table.table_head>
          <Shadix.Components.DataTable.data_table_column_header
            label="Name"
            sort={@sort_dir_for_name}
            on_sort={JS.push("sort", value: %{field: "name"})}
          />
        </Shadix.Components.Table.table_head>
      </Shadix.Components.Table.table_row>
    </Shadix.Components.Table.table_header>
    <Shadix.Components.Table.table_body>
      <Shadix.Components.Table.table_row :for={row <- @rows}>
        <Shadix.Components.Table.table_cell>{row.name}</Shadix.Components.Table.table_cell>
      </Shadix.Components.Table.table_row>
    </Shadix.Components.Table.table_body>
  </Shadix.Components.Table.table>
</Shadix.Components.DataTable.data_table>

<Shadix.Components.DataTable.data_table_pagination
  page={@page}
  total_pages={@total_pages}
  prev_disabled={@page <= 1}
  next_disabled={@page >= @total_pages}
  on_prev={JS.push("prev_page")}
  on_next={JS.push("next_page")}
/>

Summary

Functions

A bordered container for a data table.

A sortable column header button for use inside a table_head.

An optional pagination bar with prev/next buttons and a "Page X of Y" label.

Functions

data_table(assigns)

A bordered container for a data table.

Renders a rounded-md border wrapper carrying data-slot="data-table". Place a <Shadix.Components.Table.table> inside via the inner block; the table's own scroll container nests cleanly within the rounded border.

Attributes

  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • inner_block (required)

data_table_column_header(assigns)

A sortable column header button for use inside a table_head.

Renders a <button data-slot="data-table-column-header"> showing :label and a chevron reflecting :sort:

  • "asc" — up chevron
  • "desc" — down chevron
  • nil (default) — neutral up/down chevrons

Clicking runs the caller's :on_sort JS. The component is "controlled": it renders the sort state you give it and does not toggle anything itself — your handler computes the next direction and passes back an updated :sort.

The button carries an aria-label describing the sort control (and the current direction). aria-sort is not placed on the button — it is not a valid attribute there; set it on the consuming <th>/table_head instead.

Attributes

  • label (:string) (required)
  • sort (:string) - Current sort direction for this column: "asc", "desc", or nil. Defaults to nil. Must be one of "asc", "desc", or nil.
  • on_sort (Phoenix.LiveView.JS) - JS run when the header is clicked. Defaults to %Phoenix.LiveView.JS{ops: []}.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.

data_table_pagination(assigns)

An optional pagination bar with prev/next buttons and a "Page X of Y" label.

Purely presentational and "controlled": it renders :page / :total_pages and runs :on_prev / :on_next. Disable the edges with :prev_disabled / :next_disabled; your handlers update the page state you pass back in.

Attributes

  • page (:integer) - Defaults to 1.
  • total_pages (:integer) - Defaults to 1.
  • prev_disabled (:boolean) - Defaults to false.
  • next_disabled (:boolean) - Defaults to false.
  • on_prev (Phoenix.LiveView.JS) - JS run when the previous-page button is clicked. Defaults to %Phoenix.LiveView.JS{ops: []}.
  • on_next (Phoenix.LiveView.JS) - JS run when the next-page button is clicked. Defaults to %Phoenix.LiveView.JS{ops: []}.
  • class (:string) - Defaults to nil.
  • Global attributes are accepted.