The collection component, used as <Cinder.collection>. Its attributes and slots are listed
below.
layout chooses how records are shown, and every layout shares filtering, sorting, search and
pagination:
:table(the default): each<:col>is a column, and clicking a heading sorts by it.:listand:grid: an<:item>slot shows each record, and the<:col>slots only say which fields can be filtered, sorted and searched. Sorting is a row of buttons above the items.
<Cinder.collection resource={MyApp.User} actor={@current_user}>
<:col :let={user} field="name" filter sort>{user.name}</:col>
<:col :let={user} field="email" filter>{user.email}</:col>
</Cinder.collection>
<Cinder.collection resource={MyApp.Product} actor={@current_user} layout={:grid} grid_columns={4}>
<:col field="name" filter sort search />
<:col field="category" filter />
<:item :let={product}>
<h3 class="font-bold">{product.name}</h3>
<p>{product.category}</p>
</:item>
</Cinder.collection>The :controls slot lays out the filters and search box yourself, with the helpers in
Cinder.Controls:
<Cinder.collection resource={MyApp.User} actor={@current_user}>
<:col :let={user} field="name" filter sort search>{user.name}</:col>
<:col :let={user} field="status" filter={:select}>{user.status}</:col>
<:controls :let={controls}>
<Cinder.Controls.render_header {controls} />
<Cinder.Controls.render_search search={controls.search} theme={controls.theme} target={controls.target} />
<div class="grid grid-cols-2 gap-4">
<Cinder.Controls.render_filter
:for={{_field, filter} <- controls.filters}
filter={filter}
theme={controls.theme}
target={controls.target}
raw_filter_params={controls.raw_filter_params}
/>
</div>
</:controls>
</Cinder.collection>See the Getting Started, Filters, Sorting and Advanced Features guides for each feature.
Summary
Functions
Builds the list of columns used for query operations (filtering AND searching).
Process column definitions into the format expected by the underlying component.
Process filter-only slot definitions into the format expected by the filter system.
Process unified search configuration into individual components. Returns {label, placeholder, enabled, search_fn}.
Functions
Builds the list of columns used for query operations (filtering AND searching).
This function combines:
- Filterable columns: needed for filter application
- Searchable columns: needed for search even if not filterable
- Filter-only slots: dedicated filter controls not tied to display columns
NOTE: Sortable-only columns are NOT included here - sorting uses display_columns because sort controls are tied to column headers.
Raises ArgumentError if the same field is defined in both a filterable column
and a filter-only slot.
Attributes
resource(:atom) - The Ash resource to query (use either resource or query, not both). Defaults tonil.query(:any) - The Ash query to execute (use either resource or query, not both). Defaults tonil.action(:atom) - The read action to use. Defaults to the primary read action. Defaults tonil.actor(:any) - Actor for authorization. Defaults tonil.tenant(:any) - Tenant for multi-tenant resources. Defaults tonil.scope(:any) - An Ash scope, for the actor, tenant and context. Defaults tonil.layout(:any) - Layout type: :table, :list, or :grid (also accepts strings). Defaults to:table.id(:string) - The collection's id. Each collection on a page needs its own. Defaults to"cinder-collection".page_size(:any) - Records per page: a number, or[default: 25, options: [10, 25, 50]]to let users choose. Defaults toconfig :cinder, default_page_size, or 25. Defaults tonil.theme(:any) - A built-in theme's name, or a module usingCinder.Theme. Defaults toconfig :cinder, default_theme. Defaults to"default".url_state(:any) -@url_state, assigned byuse Cinder.UrlSync, to keep the collection's state in the URL. Defaults tofalse.query_opts(:list) - Additional Ash query options::load,:select,:tenant,:timeout,:authorize?,:max_concurrencyand:tracer. Any other key logs a warning and is ignored. Columns' fields are loaded already;:loadis for anything else slots show. Defaults to[].initial_load(:any) - :async (default) loads data after the page renders; :sync loads it before, putting the first page of data in the server-rendered HTML at the cost of blocking the mount. Can also be set globally viaconfig :cinder, default_initial_load: :sync. Defaults tonil.on_state_change(:any) - The message sent to the parent when filters, sorting or the page change, as{name, id, encoded_state}.Cinder.UrlSyncrelies on its own, so leave this unset on a URL-synced collection. Defaults tonil.on_query_change(:any) - Event name sent to parent when the query changes. Parent receives {event_name, %{query: Ash.Query.t(), count: integer() | nil, id: string()}}. Defaults tonil.show_pagination(:boolean) - Whether to show pagination controls. Defaults totrue.pagination(:any) - Pagination mode: :offset (default) or :keyset. Keyset pagination is faster for large datasets but only supports prev/next navigation. Also accepts a keyword list:[mode: :keyset, count: :async], wherecountis true (default, counted with each page), :async (counted in the background) or false (never counted). Defaults to:offset.show_filters(:any) - Controls filter visibility. true = always visible, false = hidden, nil = auto-detect, :toggle/"toggle" = collapsible starting collapsed, :toggle_open/"toggle_open" = collapsible starting expanded. Can also be set globally viaconfig :cinder, show_filters: :toggle. Defaults tonil.show_sort(:boolean) - Whether to show sort controls (auto-detected if nil, list/grid only). Defaults tonil.sort_mode(:any) - How sorting by another column combines with the current sort: :additive adds to it, :exclusive replaces it (also accepts strings). Defaults to:additive. Must be one of:additive,:exclusive,"additive", or"exclusive".loading_message(:string) - Message to show while loading. Defaults tonil.filters_label(:string) - Label for the filters component (defaults to translated "Filters"). Defaults tonil.sort_label(:string) - Label for sort button group (defaults to translated "Sort by:"). Defaults tonil.search(:any) - The search box: shown when a column hassearch.falsehides it, and[label: ..., placeholder: ..., fn: ...]changes its label and placeholder, or searches with your ownfn(query, searchable_columns, text). Defaults tonil.empty_message(:string) - Message to show when no results. Defaults tonil.error_message(:string) - Message to show on error. Defaults tonil.class(:string) - Additional CSS classes for the outer container. Defaults to"".container_class(:string) - Override the item container CSS class (list/grid only). Defaults tonil.grid_columns(:any) - Number of grid columns. Integer (e.g., 4) or keyword list (e.g., [xs: 1, md: 2, lg: 3]). Defaults to[xs: 1, md: 2, lg: 3].click(:any) - Function to call when a row/item is clicked. Receives the item as argument. Defaults tonil.item_class(:any) - CSS class(es) for each row/item. A string, or afn item -> class endfunction evaluated per item, appended to the theme's row/item class. Defaults tonil.id_field(:atom) - The field identifying each record, for selection and theCinder.Updatefunctions. Defaults to:id.selectable(:any) - Enable row/item selection via checkboxes. Acceptstrue/falseto enable for all rows, or a predicatefn item -> boolean endto make only matching rows selectable. Defaults tofalse.on_selection_change(:any) - Event name (atom or string) sent to parent when selection changes. Parent receives {event_name, %{selected_ids: MapSet.t(), selected_count: integer(), component_id: string(), action: atom()}}. Defaults tonil.
Slots
col- Accepts attributes:field(:string) - Field name (supports dot notation for relationships or__for embedded attributes).filter(:any) - Enable filtering (true, false, filter type atom, or unified config).sort(:any) - Enable sorting (true, false, or unified config [cycle: [nil, :asc, :desc], then: ["inserted_at"]]).search(:boolean) - Enable global search on this column.label(:string) - Custom column label (auto-generated if not provided).class(:string) - CSS classes for table column (table layout only).
item- Template for rendering each item (required for list/grid layouts).filter- Filter-only slots for filtering without display columns. Accepts attributes:field(:string) (required) - Field name to filter on.type(:any) - Filter type, as an atom or string (:text,:select, ...): from the field's type if not given.label(:string) - Custom filter label.options(:list) -{label, value}tuples, for filters that list options.value(:any) - Default or fixed value for checkbox filters.operator(:atom) - Text filter operator: :contains (default), :starts_with, :ends_with or :equals.case_sensitive(:boolean) - Whether text filtering is case-sensitive.placeholder(:string) - Placeholder text for filter input.labels(:map) - Custom labels for boolean filter options.prompt(:string) - Prompt text for select filters.match_mode(:atom) - Match mode for multi-value filters (:any or :all).include_time(:boolean) - Whether to include time in date filters.step(:any) - Step value for number range filters.min(:any) - Minimum value for range filters.max(:any) - Maximum value for range filters.max_results(:integer) - Maximum number of options an autocomplete filter shows.fn(:fun) - Custom filter function (fn query, filter_config -> query).
bulk_action- Accepts attributes:action(:any) (required) - Ash action atom or function/2 receiving (query, opts) like code interface functions.label(:string) - Button label text. Supports {count} interpolation. If provided, renders a themed button.variant(:atom) - Button style: :primary (solid), :secondary (outline), :danger (destructive). Default: :primary. Must be one of:primary,:secondary, or:danger.action_opts(:list) - Additional options passed to the Ash action (e.g., [return_records?: true, notify?: true]).confirm(:string) - Confirmation message. Supports {count} interpolation for selected count.on_success(:atom) - Message name sent to parent via handle_info on success. Payload: %{component_id, action, count, result}.on_error(:atom) - Message name sent to parent via handle_info on error. Payload: %{component_id, action, reason, partial}.
controls- Custom layout for the filter/search controls area. Receives a controls data map via :let with filters, search, and metadata. Use Cinder.Controls helpers to render individual filters, search, and headers.loading- Custom loading state content.empty- Custom empty state content.error- Custom error state content.
Process column definitions into the format expected by the underlying component.
Process filter-only slot definitions into the format expected by the filter system.
Process unified search configuration into individual components. Returns {label, placeholder, enabled, search_fn}.