Theming
View SourceCinder provides a comprehensive theming system that allows complete visual customization of your tables. With 10 built-in themes and a powerful DSL for creating custom themes, you can match any design system or create unique visual experiences.
See Also: Theme Showcase - Visual examples and comparisons of all built-in themes
Table of Contents
- Quick Start
- Built-in Theme Presets
- Custom Themes with DSL
- Theme Inheritance
- Developer Tools
- Component Reference
Quick Start
Using Built-in Themes
The fastest way to style your table is with one of the 10 built-in themes:
<Cinder.collection theme="modern" 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>Custom Theme Module
Create reusable themes with the Cinder DSL:
defmodule MyApp.CustomTheme do
use Cinder.Theme
set :container_class, "bg-white shadow-lg rounded-lg border"
set :th_class, "px-6 py-4 bg-gray-50 font-semibold text-gray-900"
set :row_class, "hover:bg-gray-50 transition-colors"
end
# Use in your template
<Cinder.collection theme={MyApp.CustomTheme} resource={MyApp.User} actor={@current_user}>
<:col :let={user} field="name" filter sort>{user.name}</:col>
</Cinder.collection>Styling Prerequisites
Tailwind CSS Forms Plugin
For consistent styling of checkboxes, radio buttons, and other form inputs across browsers, we recommend enabling the @tailwindcss/forms plugin.
Why? Native HTML checkboxes and radio buttons ignore most CSS properties (border, background, border-radius). The forms plugin applies appearance-none and provides base styles that make these inputs fully customizable with Tailwind classes.
Add to your app.css:
@plugin "@tailwindcss/forms";Note: Cinder themes work without this plugin, but checkbox and radio button styling will fall back to browser defaults. If you're using DaisyUI or Flowbite, their component classes handle form input styling internally for their own components.
Built-in Theme Presets
Cinder includes 10 carefully crafted themes covering a wide range of design styles. Each theme provides complete coverage for all table components while maintaining a consistent visual identity.
Visual Reference: See the Theme Showcase for detailed visual examples and feature descriptions of each theme.
Available themes:
"default"- Clean, minimal styling for universal compatibility"modern"- Professional styling with shadows and improved spacing"dark"- Elegant dark theme with proper contrast"daisy_ui"- Optimized for DaisyUI component library"flowbite"- Designed for Flowbite design system"retro"- Cyberpunk-inspired with bright accent colors"futuristic"- Sci-fi aesthetic with glowing effects"compact"- High-density layout for data-heavy applications
Usage
<!-- Use any theme by name -->
<Cinder.collection theme="modern" 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>Custom Themes with DSL
Create powerful, maintainable themes using Cinder's DSL syntax:
Basic Theme Structure
defmodule MyApp.Theme.Corporate do
use Cinder.Theme
# Table
set :container_class, "bg-white shadow-lg rounded-lg border border-gray-200"
set :th_class, "px-6 py-4 bg-blue-50 text-left font-semibold text-blue-900"
set :td_class, "px-6 py-4 border-b border-gray-100 text-gray-900"
set :row_class, "hover:bg-blue-50 transition-colors duration-150"
# Filters
set :filter_container_class, "bg-blue-50 border border-blue-200 rounded-lg p-6 mb-6"
set :filter_title_class, "text-lg font-semibold text-blue-900 mb-4"
set :filter_text_input_class, "w-full px-4 py-3 border border-blue-300 rounded-lg focus:ring-2 focus:ring-blue-500"
# Pagination
set :pagination_button_class, "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
set :pagination_info_class, "text-blue-700 font-medium"
endComponent-Specific Customization
Customize only the components you need:
defmodule MyApp.Theme.FilterFocused do
use Cinder.Theme
# Only customize filters, leave table and pagination with defaults
set :filter_container_class, "bg-gradient-to-r from-purple-50 to-pink-50 border-2 border-purple-200 rounded-xl p-8 mb-8"
set :filter_title_class, "text-xl font-bold text-purple-900 mb-6"
set :filter_text_input_class, "w-full px-4 py-3 border-2 border-purple-300 rounded-lg focus:ring-4 focus:ring-purple-200"
set :filter_boolean_container_class, "flex space-x-6 bg-white p-4 rounded-lg shadow-sm"
set :filter_boolean_radio_class, "h-5 w-5 text-purple-600 focus:ring-purple-500"
endTheme Inheritance
Build upon existing themes using the extends directive:
Extending Built-in Themes
defmodule MyApp.Theme.DarkModern do
use Cinder.Theme
extends :modern
# Table
set :container_class, "bg-gray-900 shadow-xl rounded-lg border border-gray-700"
set :th_class, "px-6 py-4 bg-gray-800 text-left font-semibold text-gray-100 border-b border-gray-700"
set :td_class, "px-6 py-4 text-gray-200 border-b border-gray-700"
set :row_class, "hover:bg-gray-800 transition-colors"
# Filters
set :filter_container_class, "bg-gray-800 border border-gray-700 rounded-lg p-6 mb-6"
set :filter_title_class, "text-sm font-medium text-gray-200"
set :filter_text_input_class, "w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-gray-200 focus:ring-2 focus:ring-blue-500"
endExtending Custom Themes
defmodule MyApp.Theme.CorporateCompact do
use Cinder.Theme
extends MyApp.Theme.Corporate
# Make the corporate theme more compact
set :th_class, "px-4 py-2 bg-blue-50 text-left font-semibold text-blue-900 border-b border-blue-200"
set :td_class, "px-4 py-2 border-b border-gray-100 text-gray-900"
set :filter_container_class, "bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4"
endDeveloper Tools
Cinder includes built-in developer tools to make theme creation effortless:
Data Attributes
Every themed element includes a data-key attribute identifying which theme property controls it:
<div class="bg-white shadow-lg rounded-lg" data-key="container_class">
<table class="w-full border-collapse" data-key="table_class">
<thead class="bg-gray-50" data-key="thead_class">
<tr class="border-b" data-key="header_row_class">
<th class="px-6 py-4 font-semibold" data-key="th_class">Name</th>
</tr>
</thead>
</table>
</div>Using Browser Dev Tools
- Inspect any element in your table
- Look for the
data-keyattribute to see which theme property controls it - Update your theme with the identified property name
- See changes immediately without guessing
Example workflow:
# 1. Inspect element in browser
<input data-key="filter_text_input_class" class="w-full px-3 py-2 border">
# 2. Update your theme
set :filter_text_input_class, "w-full px-4 py-3 border-2 border-blue-500 rounded-lg"
# 3. Refresh to see changes
Component Reference
All Theme Properties
set :bulk_actions_container_class, "p-4 bg-white border border-gray-200 rounded-lg shadow-sm flex gap-2 justify-end"
set :button_class, "px-3 py-1.5 text-sm font-medium rounded"
set :button_danger_class, "bg-red-600 text-white hover:bg-red-700"
set :button_disabled_class, "opacity-50 cursor-not-allowed"
set :button_primary_class, "bg-blue-600 text-white hover:bg-blue-700"
set :button_secondary_class, "border border-gray-300 text-gray-700 hover:bg-gray-50"
set :container_class, ""
set :controls_class, ""
set :empty_class, "text-center py-4"
set :error_container_class, "text-red-600 text-sm"
set :error_message_class, ""
set :filter_boolean_container_class, ""
set :filter_boolean_label_class, ""
set :filter_boolean_option_class, ""
set :filter_boolean_radio_class, ""
set :filter_checkbox_container_class, ""
set :filter_checkbox_input_class, ""
set :filter_checkbox_label_class, ""
set :filter_clear_all_class, ""
set :filter_clear_button_class, ""
set :filter_container_class, ""
set :filter_count_class, ""
set :filter_date_input_class, ""
set :filter_header_class, ""
set :filter_input_wrapper_class, ""
set :filter_inputs_class, ""
set :filter_label_class, ""
set :filter_multicheckboxes_checkbox_class, ""
set :filter_multicheckboxes_container_class, ""
set :filter_multicheckboxes_label_class, ""
set :filter_multicheckboxes_option_class, ""
set :filter_multiselect_checkbox_class, ""
set :filter_multiselect_container_class, ""
set :filter_multiselect_dropdown_class, ""
set :filter_multiselect_empty_class, ""
set :filter_multiselect_label_class, ""
set :filter_multiselect_option_class, ""
set :filter_number_input_class, "[&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [-moz-appearance:textfield]"
set :filter_placeholder_class, ""
set :filter_range_container_class, ""
set :filter_range_input_group_class, ""
set :filter_range_separator_class, "flex items-center px-2 text-sm text-gray-500"
set :filter_select_arrow_class, "w-4 h-4 ml-2 flex-shrink-0"
set :filter_select_container_class, ""
set :filter_select_dropdown_class, ""
set :filter_select_empty_class, ""
set :filter_select_input_class, ""
set :filter_select_label_class, ""
set :filter_select_option_class, ""
set :filter_select_placeholder_class, "text-gray-400"
set :filter_text_input_class, ""
set :filter_title_class, ""
set :grid_container_class, "grid gap-4"
set :grid_item_class, "p-4 bg-white border border-gray-200 rounded-lg shadow-sm"
set :grid_item_clickable_class, "cursor-pointer hover:shadow-md transition-shadow"
set :grid_selection_overlay_class, "mb-2"
set :header_row_class, ""
set :list_container_class, "divide-y divide-gray-200"
set :list_item_class, "py-3 px-4 text-gray-900"
set :list_item_clickable_class, "cursor-pointer hover:bg-gray-50 transition-colors"
set :list_selection_container_class, "mb-2"
set :loading_class, "text-center py-4"
set :loading_container_class, ""
set :loading_overlay_class, ""
set :loading_spinner_circle_class, ""
set :loading_spinner_class, ""
set :loading_spinner_path_class, ""
set :page_size_container_class, ""
set :page_size_dropdown_class, ""
set :page_size_dropdown_container_class, ""
set :page_size_label_class, ""
set :page_size_option_class, ""
set :page_size_selected_class, ""
set :pagination_button_class, ""
set :pagination_container_class, ""
set :pagination_count_class, ""
set :pagination_current_class, ""
set :pagination_info_class, ""
set :pagination_nav_class, ""
set :pagination_wrapper_class, ""
set :row_class, ""
set :search_container_class, ""
set :search_icon_class, "w-4 h-4"
set :search_input_class, "w-full px-3 py-2 border rounded"
set :search_label_class, ""
set :search_wrapper_class, "relative"
set :selected_item_class, "ring-2 ring-blue-500"
set :selected_row_class, "bg-blue-50"
set :selection_checkbox_class, "w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
set :sort_arrow_wrapper_class, "inline-flex items-center"
set :sort_asc_icon, "↑"
set :sort_asc_icon_class, "w-3 h-3"
set :sort_asc_icon_name, "hero-chevron-up"
set :sort_button_active_class, "bg-blue-50 border-blue-300 text-blue-700"
set :sort_button_class, "px-3 py-1 text-sm border rounded transition-colors"
set :sort_button_inactive_class, "bg-white border-gray-300 hover:bg-gray-50"
set :sort_buttons_class, "flex gap-1"
set :sort_container_class, "bg-white border border-gray-200 rounded-lg shadow-sm mt-4"
set :sort_controls_class, "flex items-center gap-2 p-4"
set :sort_controls_label_class, "text-sm text-gray-600 font-medium"
set :sort_desc_icon, "↓"
set :sort_desc_icon_class, "w-3 h-3"
set :sort_desc_icon_name, "hero-chevron-down"
set :sort_icon_class, "ml-1"
set :sort_indicator_class, "ml-1 inline-flex items-center align-baseline"
set :sort_none_icon_class, "w-3 h-3 opacity-50"
set :sort_none_icon_name, "hero-chevron-up-down"
set :table_class, "w-full border-collapse"
set :table_wrapper_class, "overflow-x-auto"
set :tbody_class, ""
set :td_class, ""
set :th_class, "text-left whitespace-nowrap"
set :thead_class, ""