v0.18.1 (2026-01-11)
Bug fixes
- Fixes for the DaisyUI theme: striped rows don't spill out of the table container, card styling is consistent across controls and grid/list items, and the selected page size stays readable on hover.
- The page size dropdown now clips its options to its rounded corners in every theme.
- Default column labels for embedded fields now separate each step with
>, as relationship labels do. - Turning
selectableoff now clears the selected items. - Date range filters on relationship and embedded fields now find matching records, and include the whole of the end date; through a to-many relationship, one related record has to fall inside the range.
- Date and date range filters compare the field directly instead of casting it to a date, so a database index on the field can be used.
- Number range filters through a to-many relationship now need one related record inside the range, rather than one above the minimum and another below the maximum.
- Filters on fields whose names end in
_from,_to,_minor_maxnow filter from the form, instead of being mistaken for half of a range. - URL sync no longer leaves out a page size of 1, or a filter value of 1 on a field with "page" in its name.
- Fields with
one_ofconstraints now get a select filter of those values, instead of a text filter. - Custom filters with list values now keep them in the URL, and map values no longer crash URL-synced collections.
v0.18.0 (2026-10-28)
Breaking changes
- Cinder now requires
phoenix_live_view ~> 1.1, and ships a colocated hook that yourapp.jsmust register. Runmix cinder.upgrade 0.17.0 0.18.0, or see the upgrading guide. - Cinder now requires Ash 3.24.5 or later, and
ash_sql0.6.3 or later in apps that use it. - A filter that fails to build now shows the collection's error state, instead of quietly showing unfiltered results. If a collection shows its error state after upgrading, check your logs for the filter that failed.
Features
- Added
initial_load={:sync}, which puts the first page of data in the server-rendered HTML. Thanks @Alt-iOS! (#203) on_query_changepayloads now carry acountkey with the total matching records, so parents no longer need their ownAsh.count!. Thanks @mbaertschi! (#208)refresh_table/3andrefresh_tables/3acceptsilent: true, which keeps the current rows on screen without a loading indicator while the refresh runs. Thanks @Alt-iOS! (#226)- Added
remove_item/3andremove_items/3, which remove rows from a collection without re-querying, dropping them from the selection and the footer count. Thanks @Alt-iOS! (#229) paginationaccepts a keyword list, with acountoption:true(default),:asyncto count in the background, orfalseto skip the total count. Thanks @Alt-iOS! (#241)use Cinder.UrlSyncis now all a LiveView needs for URL sync, without ahandle_params/3callingCinder.UrlSync.handle_params/3.- Columns load what their fields need (relationships in the path, calculations and aggregates), so they no longer need
query_opts={[load: ...]}. (#122) - A column's
sortoption acceptsthen, tiebreaker fields sorted after all of the user's sorts, eg.sort={[then: ["inserted_at"]]}. Thanks @DGollings! (#251) - Collections emit
[:cinder, :query]and[:cinder, :count]telemetry spans, andAsh.Tracerspans that Ash's own nest inside, saying which collection loaded and with what filters. See the advanced guide.
Bugfixes
- Multi-select filters work on
listaggregates and array calculations, instead of crashing. - Multi-select filters on an array field through a relationship (like
albums.tags) match records whose related records hold the selected values. - Columns on a calculation that needs arguments are no longer offered as sortable or filterable, which failed when used.
- A collection's data load no longer copies the parent LiveView's assigns into its task once per column, which could reach gigabytes on a busy page. Thanks @DGollings! (#250)
- Text filters with
operator: :starts_withor:ends_withnow match only the start or end of the value, instead of anywhere in it. - Global search no longer repeats the query's existing filters inside every search branch, and a searchable column with an invalid field no longer stops search from narrowing a filtered query. Thanks @Alt-iOS! (#244)
- Typing in an autocomplete filter's search box no longer reloads the collection on every keystroke. Thanks @Alt-iOS! (#246)
- Clearing a date or number filter now also clears a partially typed value, and the filter's × and "Clear all" show while one is typed.
- Radio group and autocomplete filters on enum fields now list the enum's values when no
optionsare given, like select filters already did. - Multi-select filters on an array of an enum (or of
one_ofvalues) now list its values when nooptionsare given. - Number range filters'
min,maxandstepoptions now apply to both inputs, where they were ignored. - Removed date filters'
formatoption, which did nothing: browser date inputs always show dates in the user's locale. - Autocomplete filters in a
<:filter>slot now use theirmax_results, which was ignored. - A collection with
on_state_changebut nourl_statenow applies filter and sort changes, which waited for a URL change that never came. - A custom filter configured under a built-in filter's name logs its "Cannot override built-in filter type" warning when first used, so it no longer depends on
Cinder.setup/0. - Radio group filters with non-string option values (like enum atoms) now show the chosen option as selected, instead of losing it on the first click.
- Keyset pagination's "Next page" now works in apps that don't set
config :ash, default_page_type: :keyset, where it previously reloaded the first page. - Keyset pagination's "Next" button reads "Weiter", "Volgende" and "Nästa" in German, Dutch and Swedish, instead of "Next page".
- Sort keys sent by the client are now ignored unless they're a declared sortable column, so they can no longer create atoms or sort by fields that weren't defined as sortable.
- Self-closing
<:col field="..." />columns now render their field's value in table layouts, instead of crashing. - Page numbers from the URL are capped at 1,000,000, and multi-select values from the URL or a form are trimmed to the filter's options (or to 100 when it has none), so they can't make a query do unbounded work.
- Bulk actions only act on selected records that are still in the collection's
query, and the selection is cleared when thequerychanges. - A bulk action that partly fails now fires
on_errorinstead ofon_success. - Invalid bulk action events are ignored instead of crashing the collection.
- Filter values that can't be used, like an invalid date in the URL, are ignored instead of breaking the collection.
Deprecations
Cinder.UrlManager.validate_url_params/1is deprecated and will be removed in 1.0: Cinder never called it, and URL params are now bounded where they're decoded.Cinder.QueryBuilder's field helpers (validate_field_existence/2,field_exists_on_resource?/2,resolve_field_resource/2,get_calculation_info/2,calculation_sortable?/1) are deprecated and will be removed in 1.0.Cinder.Table.table/1, deprecated since 0.9, now warns at compile time, as doCinder.Table'sprocess_columns/2,process_filter_slots/2,build_query_columns/2andprocess_search_config/2(use them fromCinder.Collection).Cinder.setup/0andCinder.Filters.Registry.register_filter/2are deprecated: custom filters need no setup.Cinder.UrlManager.decode_sort/1,Cinder.UrlSync.extract_table_state/1,Cinder.Theme.validate/1,Cinder.Theme.valid_property?/1andCinder.Messages.gettext_backend/0are deprecated and will be removed in 1.0.- A column with
sort,filterorsearchon a field that can't support it now logs a warning, and will raise in 1.0.
v0.17.0 (2026-08-08)
Features
selectablenow also accepts a predicatefn item -> boolean endto make only matching rows/items selectable. Thanks @weljoda! (#186)- Added a built-in
datefilter type: a single date picker that matches one calendar day (the whole day for datetime fields). Thanks @jeroen11dijk! (#187) If you have a custom filter registered as:date, it still takes precedence but now logs a "Cannot override built-in filter type" warning at startup — rename it or switch to the built-in. - Add French translation. Thanks @mbaertschi! (#210)
Bugfixes
toggle_selectevents now validate the given ID against the data on the current page, instead of adding arbitrary client-provided ids to the selection.mix cinder.gen.filter --template=multi_checkboxesnow generates a filter based onCinder.Filters.MultiCheckboxesinstead of falling back to a text filter.- Checkbox filters are correctly vertically aligned again in non-DaisyUI themes
v0.16.0 (2026-07-15)
Breaking changes
- Removed the
sort_asc_icon,sort_desc_icon, andsort_icon_classtheme properties — list and grid layouts now render the same Heroicon sort indicators as the table (configured viasort_*_icon_name/sort_*_icon_class). See the upgrading guide for details.
Features
- Added
item_classon<Cinder.collection>(and<Cinder.Table.table>) to set a per-row/item class: a string, or afn item -> class endfunction evaluated per item, appended to the theme's row/item class.
Bugfixes
*_nils_first/*_nils_lastsort methods now render an icon in list and grid views.
v0.15.0 (2026-06-08)
Breaking changes
- Custom filters now receive embedded fields in double-underscore notation (
profile__first_name) inbuild_query/3, matching the column definition — previously they received bracket notation ("profile[:first_name]"). See the upgrading guide for details.
v0.14.0 (2026-05-14)
Breaking changes
- Function-form bulk action handlers (
<:bulk_action action={&MyApp.archive/2}>) now receive the authorization options as provided to the collection —:scope,:actor, and:tenantflow through untouched, and the handler is expected to forward them to Ash (which resolves precedence). Handlers that readopts[:actor]directly when onlyscope=was passed will need to forwardoptsto Ash or callAsh.Scope.to_opts(opts[:scope]). - Passing a
scope=value that does not implementAsh.Scope.ToOpts(e.g. a bare atom or integer) now raisesProtocol.UndefinedErrorfrom Ash, rather than being silently ignored.
Features
- Added
on_query_changecallback on<Cinder.collection>(and<Cinder.Table.table>). (#147) - Scope-supplied
:contextis now baked onto queries built by Cinder, including those exposed viaon_query_change. query_optsnow accepts:tracerto set anAsh.Tracermodule (or list of modules) for the query.- Narrowed Tailwind class scanning so projects only pay for the built-in themes they actually use.
- Switched the default theme set by
mix cinder.installfrom"modern"to"daisy_ui", aligning with Phoenix and AshAuthentication conventions. Existing projects are unaffected — only new installs pick up the new default.
Bugfixes
- Pre-prepared queries passed via
query={Ash.Query.for_read(...)}are no longer mutated by Cinder. Explicitactor=/tenant=props on<Cinder.collection>still take effect, but only via the opts handed toAsh.readat execute time — the user's query struct keeps the actor/tenant they baked on it.
Chores
- Re-worked DaisyUI theme to be more aligned with the DaisyUI look and feel
- Delegated scope/actor/tenant precedence handling to Ash, removing the internal
Cinder.AshOptionsmodule and its hand-rolled extraction logic.
Upgrading from v0.13
Run:
mix cinder.upgrade 0.13.0 0.14.0
This rewrites your assets/css/app.css (Tailwind v4) or assets/tailwind.config.js (v3) from the old broad @source "../../deps/cinder"; / "../deps/cinder/lib/**/*.*ex" to the new per-theme @import lines, automatically including whichever built-in theme matches your configured default_theme.
If you use multiple built-in themes via the theme={...} attr on individual tables, add an @import line per theme — see the Theming guide.
v0.13.0 (2026-04-27)
Features
- Respect the
:ash, :disable_async?application env when loading data (#156) - Add Spanish translation (#164)
Bugfixes
- Fix bulk actions ignoring
scope={@scope}and running withnilactor and tenant, bypassing policies that depend on either. Bulk actions now resolve the scope the same way reads do. - Validate
page_sizevalues from the URL and dropdown against the table's configuration, so they can't exceed or bypass the developer's intent. - Fix
loading_message,filters_label, andempty_messageattributes not being translated when using gettext (#165) - Sort cycles without
nil(e.g.cycle: [:asc, :desc]) now apply the first cycle value as the default sort on initial load, instead of starting unsorted (#132)
v0.12.1 (2026-03-01)
Bugfixes
- Fix "Clear all" button in
render_headernot working inside<:controls>slot
v0.12.0 (2026-03-01)
Features
- Add
<:controls>slot for custom filter/search control layouts. See the Filters guide for examples of how to use it! - Add Brazilian Portuguese translation (#134)
Bugfixes
- Fix sort cycles without
nil(e.g.[:asc, :desc]) injecting a phantom unsorted state instead of wrapping around (#132)
v0.11.1 (2026-02-21)
Features
- Add
actionattribute to collections for specifying a custom read action (#125)
Bugfixes
- Use primary read action instead of hardcoded
:readwhen no action is specified (#125)
v0.11.0 (2026-02-19)
Features
- Add collapsible filter toggle via
show_filters={:toggle}(starts collapsed) andshow_filters={:toggle_open}(starts expanded). Can be set globally viaconfig :cinder, show_filters: :toggle. - Add Danish translation (#121)
Chores
- Add missing
data-keyattributes to theme-styled elements in filters and renderers
v0.10.0 (2026-02-14)
Features
- Add new
radio_groupfilter type, for any set of mutually exclusive options. The existingbooleanfilter now delegates toradio_groupinternally. (#115) - Add
<:loading>,<:empty>, and<:error>slots for custom state content, pluserror_messageattribute (#20) - Support custom filter labels via
filter={[label: "..."]}to override the column label in the filter UI (#102)
Bugfixes
- Fix loading overlay positioning in built-in themes (#20)
Breaking Changes
Renamed
filter_boolean_*theme keys tofilter_radio_group_*. Theme keysfilter_boolean_container_class,filter_boolean_option_class,filter_boolean_radio_class, andfilter_boolean_label_classhave been renamed to theirfilter_radio_group_*equivalents. Runmix cinder.upgrade 0.9.1 0.10.0to automatically update custom themes. See the upgrading guide for details. (#115)Removed
_datatheme keys. Theme maps no longer contain_datacompanion keys (e.g.container_data,th_data). Thedata-keyattributes are now hardcoded directly in templates. If you have custom filter templates that spread_datatheme keys (e.g.{@theme.filter_text_input_data}), replace them with a hardcodeddata-keyattribute matching the_classkey name (e.g.data-key="filter_text_input_class"). See the upgrading guide for details. (#117)
Chores
- Remove unused theme keys:
loading_class,filter_placeholder_class,search_container_class,search_label_class,search_wrapper_class
v0.9.1 (2026-02-13)
Bugfixes
- Fix crash when passing a struct as scope (#110)
- Fix query actor not being respected when no explicit actor or scope actor provided (#111)
- Fix sorting on relationship fields, calculations, and aggregates (#111)
v0.9.0 (2026-02-03)
Bugfixes
- Fix association between checkbox/label for multi-checkboxes filter (#103)
v0.9.0-beta.6 (2026-01-28)
Features
- Add
sort_modeattribute to switch between additive (default) and exclusive sorting (#98)
Bugfixes
- Fix
filter_optionsbeing added multiple times and at the incorrect level (#100) - Fix missing localization for filter placeholders and page size selector (#92)
- Fix styling of filter container in DaisyUI theme (#101)
v0.9.0-beta.5 (2026-01-27)
Features
- Add bulk selection and actions via
selectableattribute andbulk_actionslot
Bugfixes
- Add
for/idattributes to filter labels and inputs for accessibility (#91) - Fix
match_modeoption being ignored for multi-select filters on relationship fields
v0.9.0-beta.4 (2026-01-26)
Features
- Add i18n support for "Filters" and "Sort by:" labels
Improvements
- Simplify theme DSL - flat
set :property, "value"syntax replacescomponentblocks- Run
mix cinder.upgrade 0.8.1 0.9.0to automatically migrate custom themes
- Run
- Improve checkbox and radio button styling across all themes for consistent appearance with
@tailwindcss/formsplugin - Update Flowbite theme to use Flowbite design token classes for form inputs
Bugfixes
- Always include
gridCSS class when usinggridcollection layout - Fix DaisyUI theme missing padding on grid/list items by adding
card-bodyclass - Fix select/multi-select filters not using column label for default prompt
- Fix checkbox/boolean filter layout causing uneven wrapping across all themes
- Fix page size dropdown toggling all tables when multiple tables exist on same page (#89)
v0.9.0-beta.3 (2026-01-21)
Features
- Add global default page size configuration via
config :cinder, default_page_size: ...(#84) - Add in-memory item updates for efficient PubSub-driven changes without re-querying the entire table (#77)
update_item/4andupdate_items/4for direct updatesupdate_if_visible/4andupdate_items_if_visible/4for lazy loading patterns
Bug fixes
- Fix sort indicators not displaying for embedded field default sorts (#83)
- Raise helpful error for invalid filter types instead of silently falling back to text filter
- Fix custom
fnattribute on filter-only slots not being passed to QueryBuilder - Pass the full provided scope to
Ash.readwhen running queries (#71) - Fix table reloading data unnecessarily when parent LiveView re-renders with unchanged state
v0.9.0-beta.2 (2025-12-16)
Features
- Add keyset pagination support via
pagination="keyset"for better performance on large datasets (#15) - Allow filters for non-existent fields when a custom
filter_fnis attached - Add basic
autocompletefilter type, for searchable dropdowns with large preloaded option lists
v0.9.0-beta.1 (2025-12-15)
Features
- Add unified
Cinder.collectioncomponent supporting table, list, and grid layouts (#9)
Deprecations
Cinder.Table.tableis deprecated in favor ofCinder.collectionCinder.Table.UrlSyncandCinder.Table.Refreshare deprecated in favor ofCinder.UrlSyncandCinder.Refresh
See the Upgrading Guide for migration instructions.
v0.8.1 (2025-12-04)
Bug fixes
- Fix page size resetting to default when parent LiveView re-renders - user-selected page size now persists across parent state changes
- Fix filters section not showing automatically when search is enabled but no filterable columns exist (#70)
v0.8.0 (2025-11-08)
Features
- Add i18n support with gettext (#53)
Bug fixes
- Fix URL sync overwriting existing query parameters instead of merging them - custom query parameters (like
?tab=overview) are now preserved when table state changes while allowing filters to be properly cleared (#67) - Fix custom theme extension with
extendsby usingCode.ensure_loaded/1to load modules before checking forresolve_theme/0(#64) - Use existing
filter_placeholder_classtheme key for selects/multiselects when no value is selected
v0.7.2 (2025-09-30)
Bug fixes
- Fix date range filters not converting end dates to end-of-day for datetime fields, causing records on the end date to be excluded
- Fix filter forms using browser submit when the enter key is pressed (#65)
v0.7.1 (2025-09-28)
Bug fixes
- Fix filter-only slots not receiving
optionsattribute, causing select filters to show "No options available" - Ensure that field names have special characters stripped before being used in HTML attributes (#62)
- Remove double-processing of select/multi-select options and ensure that falsy values are still processed (#63)
v0.7.0 (2025-09-24)
Features
- Add filter-only slots for filtering on fields without displaying them as columns (#34)
Changes
- Remove "All" option from boolean filters - this is equivalent to clearing the filter
- Use labels when generating options from
Ash.Type.Enummodules, instead of descriptions (#35)
Bug fixes
- Fix checkbox filters in filter-only slots not applying on first click when URL sync is enabled
- Fix sorting regression where sort-only columns were not sortable via URL parameters
- Fix aggregate field type inference using wrong property name (aggregates now correctly infer as
:number_rangeinstead of:text) - Fix
show_filtersoption not being respected when rendering table (#56) - Fix search parameter not being stored in the socket after being decoded (#54)
v0.6.1 (2025-09-05)
Features
- Add custom prompt support for multi-select filters
Bug fixes
- Fix filter type inference for relationship attributes
- Fix unified filter options to default to auto-inference when no type is specified
- Fix atoms in Enum modules generating missing labels in filters (#52)
- Fix embedded field sorting using calc expressions (#51)
- Don't empty data when refreshing tables, to prevent flickering (#48)
v0.6.0 (2025-08-26)
Features
- Allow custom filter functions to be defined for a column
- Allow custom sort cycles to be defined for a column
- Allow searching multiple fields in a table at once, with a new
searchconfig option on tables and columns (#40)
Bug fixes
- Fix URL sync double processing causing duplicate data loads on sort/filter events
- Fix table refresh error when page_size on a table is set to a number (not a map of data) (#45)
- Fix table refresh resetting current sort/search state
- Add warning when table has pagination configured but Ash action lacks pagination support
v0.5.5 (2025-08-14)
Bug fixes
- Fix field validation for embedded fields using underscore notation (e.g.,
profile__first_name)
v0.5.4 (2025-08-11)
Features
- Support configurable page sizes with dropdown selector
- Use
page_size={25}for fixed page sizes (existing behaviour), orpage_size={[default: 25, options: [10, 25, 50, 100]]}for user-selectable page sizes
- Use
- Support unified filter API with options in single parameter (
filter={[type: :select, options: [...]]})- Legacy
filter_optionsparameter logs a deprecation warning, and will be removed in v1.0
- Legacy
Chores
- Support string format for filter types (e.g.,
filter="select"in addition tofilter={:select})
v0.5.3 (2025-08-07)
Bug fixes
- Fix
querynot preserving filters/sorts when usingAsh.Query.filter(Resource, ...)pattern (#36) - Ensure query tenant context is properly recognized
v0.5.2 (2025-08-06)
Bug fixes
- Log warnings about invalid column config in all environments, at the
infolog level
v0.5.1 (2025-08-03)
Features
- Allow
🔍 Filterstext to be customized via newfilters_labeltable assign (#26) - Set up the "modern" theme by default (#27)
Bug fixes
- Merge provided
filter_optionswith default options for a column, instead of overwriting them - Fix slight input jumping issues across all themes and duplicate select arrows from DaisyUI theme
- Load all records for actions without pagination configured, showing a performance warning message
- Fix crashes when attempting to sort or filter by invalid fields, such as in-memory calculations or non-existent attributes (#32)
Chores
- Replace native select boxes with custom HTML implementation for better customizability
- Add
cinderto theimport_depslist for custom formatting, on installation - Use the provided
empty_messageandloading_messagewhen rendering the table (#25)
v0.5.0 (2025-07-26)
Features
- Add
match_modeoption to multi-select and multi-checkboxes filters for array fields
Bug fixes
- Fix compilation issue caused by other libraries redefining the
uuidshortcode (#17) - Cast all string-like fields to string before using them in queries. (#8)
- Filters for array fields should be
filter_val in field_name, notfield_name in filter_val, eg."suspense" in tags
v0.4.0 (2025-06-27)
Features
- Support working with embedded attributes via a new
__notation - Add action column support - columns can now omit the
fieldattribute to create action columns with buttons, links, and other interactive elements - Add
Cinder.Table.Refreshto refresh table data while maintaining filters, sorting, and pagination state
Bug fixes
- Fix multiselect dropdowns not being visible outside the filter container
- Allow table sorting to override predefined sorts on a provided query
v0.3.0 (2025-06-23)
Features
- Add
row_clickoption forCinder.Table.table, to make entire rows clickable - Support
scopeandtenantoptions toCinder.Table.tabletenantcan also be passed in as part of thequery_optsoption
- Support
timeout,authorize?, andmax_concurrencyoptions inquery_opts
Bug fixes
- Tweaked layout of filters to avoid overlapping input content
v0.2.1 (2025-06-19)
Features
- Default to
date_rangefields for all datetime-related types
Bug fixes
- Prevent crashing when an error occurs while loading table data - the error will be properly logged instead
- Fix errors when attempting to filter on
NaiveDatetimeattribute
v0.2.0 (2025-06-18)
Features
- Allow a default theme to be specified for all tables, in application config (eg.
config :cinder, default_theme: "dark") - Reorder arguments to
UrlSync.handle_paramsto be consistent with LiveView'shandle_params- Replace
Cinder.Table.UrlSync.handle_params(socket, params, url)withCinder.Table.UrlSync.handle_params(params, uri, socket)
- Replace
v0.1.1 (2025-06-16)
Bug fixes
- Fix bug where invalid sorts would sometimes raise
(Protocol.UndefinedError) protocol String.Chars not implemented for type Ash.Query (a struct) - Fix incorrect environment specification for
sourcererandigniterdependencies - these should only ever be installed indevandtest - Fix styling of table row borders in
flowbitetheme (light mode)
v0.1.0 (2025-06-15)
- Initial release