ListBuilder Styling
Complete guide for customizing list appearance using the field-first pattern. Lists display data as Bootstrap cards in a responsive grid layout. Apply CSS classes directly to fields and boxes with clean, readable code.
Understanding List Structure
The list plugin uses a box_attrs array to control the appearance of different elements. Here's the default structure:
| Attribute Key | Element | Default Classes |
|---|---|---|
form |
Form wrapper | card-body-overflow js-list-form container-fluid |
container |
Grid container (row) | row g-3 js-box-container |
col |
Column wrapper for each box | col-12 col-md-6 col-lg-4 |
box |
Card/box element | card h-100 js-box-item |
box.header |
Box header (checkbox + actions) | card-header d-flex justify-content-between align-items-center |
box.body |
Box body (field rows) | card-body |
box.footer |
Box footer | card-footer |
field.row |
Single field container | row mb-2 border-bottom pb-2 |
field.label |
Field label column | col-5 fw-bold text-muted |
field.value |
Field value column | col-7 |
checkbox.wrapper |
Checkbox wrapper | form-check |
Quick Start
Quick Color Themes
$list = \Builders\ListBuilder::create($model, 'products_list')
->boxColor('primary') // Blue theme
->boxColor('success') // Green theme
->boxColor('danger') // Red theme
->boxColor('warning') // Yellow theme
->getResponse();
echo $list['html'];
Custom Box Classes
$list = \Builders\ListBuilder::create($model, 'products_list')
// Combine multiple Bootstrap card classes
->boxClass('card shadow-sm border-0')
->getResponse();
echo $list['html'];
Grid Layout
Responsive Columns
$list = \Builders\ListBuilder::create($model, 'products_list')
// Set responsive grid: 1 col on mobile, 2 on tablet, $cols on desktop
->gridColumns($cols)
->getResponse();
echo $list['html'];
Note: Default is col-12 col-md-6 col-lg-4 (1 column on mobile, 2 on tablet, 3 on desktop)
Custom Container and Column Classes
$list = \Builders\ListBuilder::create($model, 'products_list')
// Customize the container wrapper
->containerClass('row g-4 justify-content-center')
// Customize individual column wrappers
->colClass('col-12 col-sm-6 col-lg-4 col-xl-3')
->getResponse();
echo $list['html'];
Box Styling
Box Component Classes
$list = \Builders\ListBuilder::create($model, 'products_list')
// Style the entire box
->boxClass('card shadow-lg border-primary')
// Style box header
->boxHeaderClass('bg-primary text-white fw-bold')
// Style box body
->boxBodyClass('bg-light')
// Style box footer
->boxFooterClass('bg-secondary text-white text-center')
->getResponse();
echo $list['html'];
Alternating Box Colors
$list = \Builders\ListBuilder::create($model, 'products_list')
// Alternate between two CSS classes
->boxClassAlternate('border-primary', 'border-success')
->getResponse();
echo $list['html'];
Conditional Box Classes
$list = \Builders\ListBuilder::create($model, 'orders_list')
// Highlight cancelled orders in red
->classByValue( 'cancelled', 'border-danger bg-danger bg-opacity-10')
// Highlight high-value orders in yellow (total > 1000)
->field('total')
->classByValue(1000, 'border-warning shadow-lg', '>')
// Supported operators: '==', '>', '<', '>=', '<=', '!=', 'contains'
->getResponse();
echo $list['html'];
Field-First Styling
The field-first pattern allows you to apply styling directly to each field using method chaining. This keeps all field configurations (data, display, and styling) in one place.
Basic Field Styling
$list = \Builders\ListBuilder::create($model, 'sales_list')
// Style specific fields
->field('amount')
->label('Total Amount')
->class('text-success fw-bold fs-5')
->field('status')
->label('Status')
->class('text-center badge bg-primary')
->field('customer_name')
->label('Customer')
->class('fw-semibold text-primary')
->getTable();
Conditional Field Styling
Apply CSS classes when a field matches a specific value using classValue().
$list = \Builders\ListBuilder::create($model, 'products_list')
// Status field with color coding
->field('status')
->label('Status')
->classValue('active', 'badge bg-success')
->classValue('inactive', 'badge bg-danger')
->classValue('pending', 'badge bg-warning')
// Stock with conditional styling
->field('stock')
->label('Stock')
->classValue(10, 'text-danger fw-bold fs-4', '<') // Red if < 10
->classValue(50, 'text-warning', '<') // Orange if < 50
->classValue(50, 'text-success', '>=') // Green if >= 50
// Price highlighting
->field('price')
->label('Price')
->classValue(100, 'text-success fs-5 fw-bold', '>') // Large green if > 100
->class('text-end')
->getTable();
// Supported operators: '==', '!=', '>', '<', '>=', '<=', 'contains'
Style Based on Another Field
Apply CSS classes to a field based on the value of a different field using classOtherValue().
$list = \Builders\ListBuilder::create($model, 'products_list')
// Highlight price when product has discount
->field('price')
->label('Price')
->classOtherValue('has_discount', true, 'text-success fw-bold fs-4')
->class('text-end')
// Show name in muted color if not in stock
->field('name')
->label('Product Name')
->classOtherValue('stock', 0, 'text-muted text-decoration-line-through')
->link('?page=products&action=edit&id=%id%')
// Highlight quantity based on stock status
->field('quantity')
->label('Quantity')
->classOtherValue('stock_status', 'low', 'text-danger fw-bold')
->classOtherValue('stock_status', 'out', 'text-danger text-decoration-line-through')
->getTable();
Global Field Classes
You can also set global styles for all field rows, labels, and values:
$list = \Builders\ListBuilder::create($model, 'products_list')
// Style all field rows
->fieldRowClass('mb-3 pb-2 border-bottom')
// Style all field labels
->fieldLabelClass('col-4 fw-bold text-primary')
// Style all field values
->fieldValueClass('col-8 text-end')
// Then override specific fields with field-first pattern
->field('price')
->label('Price')
->class('text-success fs-4 fw-bold') // Override global value class
->getResponse();
echo $list['html'];
Custom Box Template
You can replace the default box template with your own custom template file. The template receives the following variables:
$box_attrs- Array of box attributes$box_item_attrs- Specific attributes for this box (with dynamic classes)$fields_data- Array of field objects with label, value, type, classes, and attrs$checkbox- HTML for checkbox (if present)$actions- HTML for actions (if present)
Example: Custom Template for Posts
Step 1: Create the custom template file at Modules/Posts/Views/custom-box.php:
<?php
!defined('MILK_DIR') && die();
?>
<div <?php Theme\Template::addAttrs($box_attrs, 'col'); ?>>
<div <?php Theme\Template::addAttrs(['box' => $box_item_attrs], 'box'); ?>>
<div <?php Theme\Template::addAttrs($box_attrs, 'box.body'); ?>>
<h2><?php _p($fields_data['title']->value) ?></h2>
<p><?php _pt($fields_data['content']->value) ?></p>
</div>
<?php if ($checkbox || $actions) { ?>
<div <?php Theme\Template::addAttrs($box_attrs, 'box.footer'); ?>>
<?php echo $checkbox; ?>
<?php echo $actions; ?>
</div>
<?php } ?>
</div>
</div>
Step 2: Use the template in your controller:
// In PostsController.php
$response['html'] = ListBuilder::create($this->model, 'idTablePosts')
->field('content')
->truncate(50)
->gridColumns(1)
// Set custom box template
->setBoxTemplate(__DIR__ . '/Views/custom-box.php')
->setDefaultActions()
->render();
Template Variables Reference
Your custom template has access to these variables:
| Variable | Type | Description |
|---|---|---|
$box_attrs |
array | All box attributes (col, box, box.header, box.body, box.footer) |
$box_item_attrs |
array | Attributes for this specific box (includes dynamic classes) |
$fields_data |
array | Associative array: $fields_data['field_name']->value, ->label, ->type |
$checkbox |
string | HTML for checkbox (empty if no bulk actions) |
$actions |
string | HTML for row actions (empty if no actions) |
Accessing Field Data
<!-- Access specific field values -->
<?php _p($fields_data['title']->value) ?>
<?php _p($fields_data['price']->value) ?>
<?php _p($fields_data['created_at']->value) ?>
<!-- Check field type -->
<?php if ($fields_data['description']->type == 'html') {
_ph($fields_data['description']->value);
} else {
_p($fields_data['description']->value);
} ?>
<!-- Loop through all fields -->
<?php foreach ($fields_data as $field_name => $field) : ?>
<strong><?php _pt($field->label); ?>:</strong>
<?php _p($field->value); ?>
<?php endforeach; ?>
Complete Styling Example
$model = new \Models\ProductModel();
$list = \Builders\ListBuilder::create($model, 'products_list')
// Query configuration
->where('deleted = ?', [0])
->orderBy('created_at', 'desc')
->limit(24)
// Grid Layout: responsive columns
->gridColumns(3)
// Container styling
->containerClass('row g-4')
// Box-level styling
->boxClass('card h-100 shadow-sm')
->boxColor('primary')
// Conditional box highlighting
->classByValue('stock', 0, 'border-danger border-3')
->classByValue('status', 'featured', 'shadow-lg border-warning border-2')
// Box component styling
->boxHeaderClass('bg-gradient text-white')
->boxBodyClass('p-3')
// Global field styling
->fieldRowClass('mb-2 pb-2')
->fieldLabelClass('col-5 text-muted small')
->fieldValueClass('col-7 fw-semibold')
// Field-first styling for specific fields
->field('name')
->label('Product Name')
->link('?page=products&action=edit&id=%id%')
->classOtherValue('featured', true, 'fw-bold text-primary')
->field('price')
->label('Price')
->class('text-success fs-5 fw-bold text-end')
->classValue(100, 'text-danger fs-4', '>') // Extra large red if > 100
->field('stock')
->label('Stock')
->class('text-center')
->classValue(10, 'text-danger fw-bold', '<')
->classValue(0, 'badge bg-danger', '==')
->field('status')
->label('Status')
->classValue('active', 'badge bg-success')
->classValue('inactive', 'badge bg-secondary')
->classValue('featured', 'badge bg-warning text-dark')
->field('category')
->label('Category')
->class('text-muted')
// Actions
->setDefaultActions()
->getTable();
Method Reference
Field-First Styling Methods
| Method | Parameters | Description | Example |
|---|---|---|---|
field() |
$key | Select field for styling | ->field('status') |
class() |
$classes | Set CSS classes for field value | ->class('fw-bold text-primary') |
classValue() |
$value, $classes, $operator | Conditional classes based on field value | ->classValue('active', 'badge bg-success') |
classOtherValue() |
$field, $value, $classes, $operator | Conditional classes based on other field | ->classOtherValue('featured', true, 'fw-bold') |
Global Field Styling Methods
| Method | Parameters | Description |
|---|---|---|
fieldRowClass() |
$classes | CSS classes for all field row containers |
fieldLabelClass() |
$classes | CSS classes for all field labels |
fieldValueClass() |
$classes | CSS classes for all field values |
Box & Layout Methods
| Method | Parameters | Description |
|---|---|---|
boxColor() |
$color | Quick theme colors (primary, success, danger, warning, info, light, dark) |
boxClass() |
$classes | Custom CSS classes for box element |
boxHeaderClass() |
$classes | CSS classes for box header |
boxBodyClass() |
$classes | CSS classes for box body |
boxFooterClass() |
$classes | CSS classes for box footer |
boxClassAlternate() |
$odd_classes, $even_classes | Alternate box colors |
classByValue() |
$value, $classes, $operator | Conditional box classes based on field value |
containerClass() |
$classes | CSS classes for grid container |
colClass() |
$classes | CSS classes for column wrappers |
gridColumns() |
$cols | Set responsive grid columns (e.g., 2, 3, 4) |
checkboxWrapperClass() |
$classes | CSS classes for checkbox wrapper |
setBoxTemplate() |
$template_path | Set custom box template file (absolute path) |
Supported Comparison Operators
==- Equal to (default)!=- Not equal to>- Greater than<- Less than>=- Greater than or equal to<=- Less than or equal tocontains- String contains value
Best Practices
- Use field-first pattern: Keep all configuration for a field (label, type, styling) together
- Combine global and specific styling: Set global field styles with fieldLabelClass(), then override specific fields with field()->class()
- Use semantic classes: Prefer Bootstrap utility classes (badge, text-success) for consistency
- Chain multiple classValue(): Apply different styles for different conditions on the same field
- Test responsive grid: Use gridColumns() to ensure proper display on all devices
- Accessibility: Don't rely solely on color; use text, icons, or badges for critical information