# Data Table

The server-driven table: DataTable::State.from_params with a sortable: whitelist, URL-state sorting, filtering and pagination, row selection, and sticky headers - a full controller-to-view recipe.

`Poetry::Ui::DataTable::State.from_params(params, sortable: %w[...])` sanitizes at the door - `sort` survives only the whitelist, `dir` only asc/desc - so `state.order_clause` is injection-safe by construction; the controller owns the scope and passes `total:` as a page count. In the view, `poetry_data_table(rows:, state:, total:, path:)` declares columns with `table.with_column("Title", key: :title, sortable: true) { |row| ... }`; a sortable key missing from the whitelist raises at render. `sticky_header: true` needs a `container_class:` height cap; `selectable:` adds a checkbox column posting `selected_ids[]`; `frame:` scopes Turbo round trips while the URL advances. Sort affordances are real links with `aria-sort`; the filter is a labelled GET form.
