Cinder.Collection (Cinder v0.12.1)

Copy Markdown View Source

Unified collection component for displaying data in table, list, or grid layouts.

This component provides a single API for all collection displays, with the layout attribute selecting how items are rendered. All layouts share the same filtering, sorting, pagination, and URL sync capabilities.

Layouts

  • :table (default) - Traditional HTML table with sortable headers
  • :list - Vertical list with sort button group
  • :grid - Responsive card grid with sort button group

Basic Usage

Table Layout (default)

<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>

List Layout

<Cinder.collection resource={MyApp.User} actor={@current_user} layout={:list}>
  <:col field="name" filter sort />
  <:col field="status" filter={:select} />

  <:item :let={user}>
    <div class="flex justify-between">
      <span class="font-bold">{user.name}</span>
      <span>{user.status}</span>
    </div>
  </:item>
</Cinder.collection>

Grid Layout

<Cinder.collection resource={MyApp.Product} actor={@current_user} layout={:grid}>
  <:col field="name" filter sort search />
  <:col field="category" filter={:select} />

  <:item :let={product}>
    <h3 class="font-bold">{product.name}</h3>
    <p class="text-gray-600">{product.category}</p>
    <p class="text-lg font-semibold">${product.price}</p>
  </:item>
</Cinder.collection>

Grid Columns

Control the number of grid columns with the grid_columns attribute:

<!-- Fixed 4 columns -->
<Cinder.collection resource={MyApp.Product} layout={:grid} grid_columns={4}>
  ...
</Cinder.collection>

<!-- Responsive columns -->
<Cinder.collection resource={MyApp.Product} layout={:grid} grid_columns={[xs: 1, md: 2, lg: 3, xl: 4]}>
  ...
</Cinder.collection>

Layout-Specific Attributes

AttributeTableListGridDescription
<:col> content✅ Rendered❌ Ignored❌ IgnoredCell content for table rows
<:item> slot❌ Ignored✅ Required✅ RequiredTemplate for each item
sort_label❌ N/A✅ Button label✅ Button labelLabel for sort button group
container_class❌ N/A✅ Override✅ OverrideCustom container CSS
grid_columns❌ N/A❌ N/A✅ Column countNumber of grid columns
click✅ Row click✅ Item click✅ Item clickClick handler

Custom Controls Layout

Use the :controls slot to customize how filters and search are rendered while keeping Cinder's state management, URL sync, and query building intact:

<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} />
    <div class="grid grid-cols-2 gap-4">
      <Cinder.Controls.render_filter
        :for={filter <- controls.filters}
        filter={filter}
      />
    </div>
  </:controls>
</Cinder.collection>

See Cinder.Controls for the full API and more examples.

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

build_query_columns(processed_columns, processed_filter_slots)

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(assigns)

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) - Ash scope containing actor and tenant. Defaults to nil.
  • layout (:any) - Layout type: :table, :list, or :grid (also accepts strings). Defaults to :table.
  • id (:string) - Unique identifier for the collection. Defaults to "cinder-collection".
  • page_size (:any) - Number of items per page or [default: 25, options: [10, 25, 50]]. See Cinder.PageSize for global configuration. Defaults to nil.
  • theme (:any) - Theme name or theme map. Defaults to "default".
  • url_state (:any) - URL state object from UrlSync.handle_params, or false to disable. Defaults to false.
  • query_opts (:list) - Additional Ash query options. Defaults to [].
  • on_state_change (:any) - Custom state change handler. 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. 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.
  • loading_message (:string) - Message to show while loading. Defaults to "Loading...".
  • 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) - Search configuration. Auto-enables when searchable columns exist. 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.
  • id_field (:atom) - Field to use as ID for update_if_visible operations (defaults to :id). Defaults to :id.
  • selectable (:boolean) - Enable row/item selection via checkboxes. 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).
    • filter_options (:list) - Custom filter options - DEPRECATED: Use filter={[type: :select, options: [...]]} instead.
    • sort (:any) - Enable sorting (true, false, or unified config [cycle: [nil, :asc, :desc]]).
    • 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 (:atom) - Filter type (:text, :select, :boolean, :date_range, etc.).
    • label (:string) - Custom filter label.
    • options (:list) - Options for select/multi_select filters.
    • value (:any) - Default or fixed value for checkbox filters.
    • operator (:atom) - Filter operator (:eq, :contains, :gt, etc.).
    • 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).
    • format (:string) - Date format for date filters.
    • 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.
    • 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}.
  • 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(col_slots, resource)

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

process_filter_slots(filter_slots, resource)

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

process_search_config(search_config, columns)

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