Full documentation for every attribute, with types and defaults, is generated from the component declarations — run mix docs or see the Slab module on HexDocs. The tables below are the quick version.

Slab.table/1 attributes

AttributeDefaultExampleDescription
idrequiredid="users-table"Unique component id
datanildata={@users}Pre-fetched records (list mode); omit for query mode
schemanilschema={MyApp.User}Ecto.Schema module for field reflection (typed rendering, filter inputs, casting); the default query-mode source
querynilquery={@scoped_query}Ecto.Query used as the base of every fetch instead of the schema — scoping, joins, computed fields
preloadnilpreload={[:products]}Associations to preload on fetched records, in any Ecto.Query.preload/3 shape
reponilrepo={MyApp.Repo}Repo for query mode; falls back to config :slab, repo: MyApp.Repo
uriniluri={@uri}Current request URI from handle_params/3; required by URL-driven slots
params%{}params={@params}Current request params from handle_params/3; carries sort/page/filter/column/selection state
on_savenilon_save={&save_user/2}2-arity (record, changed_params) -> {:ok, record} | {:error, error} called on row save; required when any column is editable
row_clicknilrow_click={fn user -> JS.navigate(~p"/users/#{user}") end}1-arity (record) -> %JS{} attached as phx-click on each data cell; skips checkbox and editable columns

<:column> slot attributes

AttributeDefaultExampleDescription
fieldnilfield={:name}Record field to render; optional for virtual columns with a body
labelhumanized fieldlabel="Full Name"Column header text
sortablefalsesortableHeader becomes a sort patch link; whitelists the field for ORDER BY in query mode
optionalfalseoptionalStarts the column hidden until enabled via the Columns tab or columns[] param
export_valuenilexport_value={&products_csv/1}1-arity (record) -> value used when exporting; makes virtual columns exportable and overrides the raw field value
editablefalseeditableRenders the cell as an input feeding the row's save action; requires a field and the table's on_save, and cannot combine with a body

Columns with a body receive the record via :let:

<:column :let={user} field={:name}>{String.upcase(user.name)}</:column>

<:column_checkbox> slot

Row-selection checkboxes, always the first column and always visible. At most one; requires uri. No attributes.

<:filter> slot attributes

AttributeDefaultExampleDescription
fieldrequiredfield={:name}Field to filter on; whitelists it for filter[...] URL params
labelhumanized fieldlabel="Full Name"Label for the Filters tab input
typederivedtype="multiselect"Input type ("text", "select", "multiselect"); "hidden" whitelists without rendering an input
optionsderivedoptions={[{"Admin", "admin"}]}Options for select/multiselect inputs; derived automatically for booleans and Ecto.Enum fields
placeholdernilplaceholder="Search..."Placeholder for the input
min_chars0min_chars={3}Minimum characters before a text filter change applies
debounce300debounce={500}Milliseconds to debounce text input changes
querynilquery={&by_org/2}Custom 2-arity (queryable, value) -> queryable filter; may join associations

<:tab> slot attributes

AttributeDefaultExampleDescription
namerequiredname="filters""filters", "columns", "share", "export", or a custom tab's identity
labelderivedlabel="Help"Tab label; derived for built-in names, required for custom tabs
iconderivedicon="bookmark-outline"Icon before the label; see Slab.Components.icon/1
countderivedcount={3}Badge count for custom tabs; built-in tabs compute their own
limit1000limit={5000}Export only: maximum rows in a full-data export

<:pagination> slot attributes

AttributeDefaultExampleDescription
type:pagetype={:cursor}:page (offset, both modes) or :cursor (keyset, query mode only); requires uri
per_page25per_page={50}Default page size
max_per_page100max_per_page={200}Upper clamp for the URL per_page param, so a crafted URL can't request unbounded rows
options[10, 25, 50, 100]options={[25, 100]}Page sizes offered in the footer dropdown (page mode)

Slab.filter/1 attributes

AttributeDefaultExampleDescription
idrequiredid="filter-name"Unique component id
fieldrequiredfield={:name}Filter key; matches a <:filter> field on the table
urirequireduri={@uri}Current request URI from handle_params/3
params%{}params={@params}Current request params; carries the input's current value
schemanilschema={MyApp.User}Derives the input type and options when not given
typederivedtype="multiselect""text", "select", or "multiselect"; derived from schema when omitted
labelnillabel="Status"Label rendered beside the input
placeholdernilplaceholder="Search..."Placeholder for the input
optionsderivedoptions={[{"Active", "true"}]}Select options, as [{label, value}] tuples or plain values
debounce300debounce={500}Milliseconds to debounce text input changes
min_chars0min_chars={3}Minimum characters before a text change applies; empty always applies (clearing the filter)

Slab.tabs/1 attributes

AttributeDefaultExampleDescription
idrequiredid="table-tabs"Unique DOM id
activefirst tabactive="Filters"Label of the initially active tab

Each <:tab> slot takes label (required), icon (optional, see Slab.Components.icon/1), and count (optional badge, hidden when zero).

Slab.share/1 attributes

AttributeDefaultExampleDescription
urirequireduri={@uri}Current request URI shown in the copyable input

URL params

The URL is Slab's state contract — every param is readable, shareable, and validated against whitelists and field types before touching a query:

ParamWritten byExample
sort, sort_directionSortable headers?sort=name&sort_direction=desc
page, per_pagePage-mode pagination?page=3&per_page=50
after[id], after[value]Cursor-mode pagination?after[id]=42&after[value]=2026-01-01T00%3A00%3A00Z
filter[field]Filter inputs?filter[name]=ada
filter[field][op]Custom filter UIs?filter[age][gte]=21
columnsColumns tab picker?columns[]=email&columns[]=name
checkedRow-selection checkboxes?checked[]=1&checked[]=42

Helper functions

FunctionDescription
Slab.sort_path(uri, params, field)Path that sorts by field, flipping direction and resetting pagination
Slab.page_path(uri, page)Path for a page number; page 1 drops the param
Slab.filter_path(uri, field, value)Path that sets/clears filter[field] and resets pagination
Slab.get_filter_count(uri_or_params)Number of active filters (for a filters tab badge)
Slab.Helpers.URI.get_query_param_count(uri)Recursive count of query params (for a share tab badge)
Slab.get_checked_ids(uri_or_params)Checked row IDs as strings
Slab.get_checked_count(uri_or_params)Number of checked rows
Slab.get_checked_values(uri, records, opts)Records whose ID is checked
Slab.checked?(uri_or_params)Whether any rows are checked
Slab.get_selected_and_missing_ids(records, ids, opts)Splits selections into current-page records and IDs to fetch (cross-page selection)