# `Cinder.Collection`
[🔗](https://github.com/sevenseacat/cinder/blob/v0.18.0/lib/cinder/collection.ex#L5)

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.
- `:list` and `: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.

```heex
<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`:

```heex
<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](getting-started.html), [Filters](filters.html),
[Sorting](sorting.html) and [Advanced Features](advanced.html) guides for each feature.

# `build_query_columns`

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.

# `collection`

## Attributes

* `resource` (`:atom`) - The Ash resource to query (use either resource or query, not both). Defaults to `nil`.
* `query` (`:any`) - The Ash query to execute (use either resource or query, not both). Defaults to `nil`.
* `action` (`:atom`) - The read action to use. Defaults to the primary read action. Defaults to `nil`.
* `actor` (`:any`) - Actor for authorization. Defaults to `nil`.
* `tenant` (`:any`) - Tenant for multi-tenant resources. Defaults to `nil`.
* `scope` (`:any`) - An Ash scope, for the actor, tenant and context. Defaults to `nil`.
* `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 to `config :cinder, default_page_size`, or 25. Defaults to `nil`.
* `theme` (`:any`) - A built-in theme's name, or a module using `Cinder.Theme`. Defaults to `config :cinder, default_theme`. Defaults to `"default"`.
* `url_state` (`:any`) - `@url_state`, assigned by `use Cinder.UrlSync`, to keep the collection's state in the URL. Defaults to `false`.
* `query_opts` (`:list`) - Additional Ash query options: `:load`, `:select`, `:tenant`, `:timeout`, `:authorize?`, `:max_concurrency` and `:tracer`. Any other key logs a warning and is ignored. Columns' fields are loaded already; `:load` is 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 via `config :cinder, default_initial_load: :sync`. Defaults to `nil`.
* `on_state_change` (`:any`) - The message sent to the parent when filters, sorting or the page change, as `{name, id, encoded_state}`. `Cinder.UrlSync` relies on its own, so leave this unset on a URL-synced collection. Defaults to `nil`.
* `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 to `nil`.
* `show_pagination` (`:boolean`) - Whether to show pagination controls. Defaults to `true`.
* `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]`, where `count` is 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 via `config :cinder, show_filters: :toggle`. Defaults to `nil`.
* `show_sort` (`:boolean`) - Whether to show sort controls (auto-detected if nil, list/grid only). Defaults to `nil`.
* `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 to `nil`.
* `filters_label` (`:string`) - Label for the filters component (defaults to translated "Filters"). Defaults to `nil`.
* `sort_label` (`:string`) - Label for sort button group (defaults to translated "Sort by:"). Defaults to `nil`.
* `search` (`:any`) - The search box: shown when a column has `search`. `false` hides it, and `[label: ..., placeholder: ..., fn: ...]` changes its label and placeholder, or searches with your own `fn(query, searchable_columns, text)`. Defaults to `nil`.
* `empty_message` (`:string`) - Message to show when no results. Defaults to `nil`.
* `error_message` (`:string`) - Message to show on error. Defaults to `nil`.
* `class` (`:string`) - Additional CSS classes for the outer container. Defaults to `""`.
* `container_class` (`:string`) - Override the item container CSS class (list/grid only). Defaults to `nil`.
* `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 to `nil`.
* `item_class` (`:any`) - CSS class(es) for each row/item. A string, or a `fn item -> class end` function evaluated per item, appended to the theme's row/item class. Defaults to `nil`.
* `id_field` (`:atom`) - The field identifying each record, for selection and the `Cinder.Update` functions. Defaults to `:id`.
* `selectable` (`:any`) - Enable row/item selection via checkboxes. Accepts `true`/`false` to enable for all rows, or a predicate `fn item -> boolean end` to make only matching rows selectable. Defaults to `false`.
* `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 to `nil`.
## 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_columns`

Process column definitions into the format expected by the underlying component.

# `process_filter_slots`

Process filter-only slot definitions into the format expected by the filter system.

# `process_search_config`

Process unified search configuration into individual components.
Returns {label, placeholder, enabled, search_fn}.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
