Skip to content

Tabler UI Components

George Dawoud edited this page Apr 27, 2026 · 1 revision

Tabler UI Components — Developer Guide

ChurchCRM 7.1.0 migrated from AdminLTE/Bootstrap 4 to Tabler + Bootstrap 5. This guide covers how to use Tabler components correctly in new and updated pages.

Important: Do not use Bootstrap 4 class names (e.g., mr-*, ml-*, pr-*, pl-*, float-left). Use Bootstrap 5 equivalents (me-*, ms-*, pe-*, ps-*, float-start).


Quick Reference: Bootstrap 4 → Bootstrap 5 Migrations

Bootstrap 4 Bootstrap 5 Notes
mr-2 me-2 Margin-end (right in LTR)
ml-2 ms-2 Margin-start (left in LTR)
pr-2 pe-2 Padding-end
pl-2 ps-2 Padding-start
float-left float-start
float-right float-end
text-left text-start
text-right text-end
form-group (removed) Use mb-3 wrapper div
form-control (select) form-select
data-toggle data-bs-toggle Bootstrap 5 data attrs
data-dismiss data-bs-dismiss
data-target data-bs-target
badge-primary bg-primary Badge colors
btn-block d-grid wrapper Block-level buttons

Card Component

Tabler extends Bootstrap 5 cards with additional helpers.

<div class="card">
    <div class="card-header">
        <h3 class="card-title"><?= gettext('Section Title') ?></h3>
        <div class="card-options">
            <!-- optional action buttons -->
            <a href="#" class="btn btn-sm btn-primary">
                <i class="ti ti-plus me-1"></i><?= gettext('Add') ?>
            </a>
        </div>
    </div>
    <div class="card-body">
        <!-- content -->
    </div>
    <div class="card-footer text-end">
        <!-- footer actions -->
    </div>
</div>

Card Variants

<!-- Elevated card (most common for data panels) -->
<div class="card card-elevated">...</div>

<!-- Status card (metric display) -->
<div class="card card-sm">
    <div class="card-body">
        <div class="row align-items-center">
            <div class="col-auto">
                <span class="bg-primary text-white avatar">
                    <i class="ti ti-users"></i>
                </span>
            </div>
            <div class="col">
                <div class="font-weight-medium">175</div>
                <div class="text-secondary">Total Members</div>
            </div>
        </div>
    </div>
</div>

Icons

ChurchCRM 7.1+ uses Tabler Icons (SVG icon font). Use the ti ti-* class prefix.

<!-- Tabler icon (preferred for new code) -->
<i class="ti ti-users"></i>
<i class="ti ti-calendar-event"></i>
<i class="ti ti-cash"></i>
<i class="ti ti-settings"></i>

<!-- Font Awesome 6 (still available for compatibility) -->
<i class="fa-solid fa-users"></i>

Find icons at: tabler.io/icons


Alerts and Notifications

<!-- Info alert -->
<div class="alert alert-info" role="alert">
    <i class="ti ti-info-circle me-2"></i>
    <?= gettext('This is an informational message.') ?>
</div>

<!-- Warning alert with dismissal -->
<div class="alert alert-warning alert-dismissible" role="alert">
    <i class="ti ti-alert-triangle me-2"></i>
    <?= gettext('Warning: check your settings.') ?>
    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>

Modals

<!-- Trigger -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#myModal">
    <?= gettext('Open Modal') ?>
</button>

<!-- Modal structure -->
<div class="modal modal-blur fade" id="myModal" tabindex="-1" role="dialog">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"><?= gettext('Modal Title') ?></h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            <div class="modal-body">
                <!-- content -->
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary me-auto" data-bs-dismiss="modal">
                    <?= gettext('Cancel') ?>
                </button>
                <button type="button" class="btn btn-primary">
                    <?= gettext('Save') ?>
                </button>
            </div>
        </div>
    </div>
</div>

Offcanvas

Offcanvas panels are used for editors that slide in from the side (added in 7.1.0 for group, event, and family editors).

<!-- Trigger -->
<button class="btn btn-sm btn-outline-primary" type="button" 
        data-bs-toggle="offcanvas" data-bs-target="#editPanel">
    <i class="ti ti-pencil me-1"></i><?= gettext('Edit') ?>
</button>

<!-- Offcanvas panel -->
<div class="offcanvas offcanvas-end" tabindex="-1" id="editPanel">
    <div class="offcanvas-header">
        <h5 class="offcanvas-title"><?= gettext('Edit Record') ?></h5>
        <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
    </div>
    <div class="offcanvas-body">
        <form>
            <!-- form fields -->
        </form>
    </div>
</div>

Tables

<div class="table-responsive">
    <table class="table table-vcenter table-hover card-table">
        <thead>
            <tr>
                <th><?= gettext('Name') ?></th>
                <th><?= gettext('Status') ?></th>
                <th class="w-1"><?= gettext('Actions') ?></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td><?= InputUtils::escapeHTML($name) ?></td>
                <td>
                    <span class="badge bg-success">Active</span>
                </td>
                <td>
                    <a href="#" class="btn btn-sm btn-outline-secondary">
                        <i class="ti ti-pencil"></i>
                    </a>
                </td>
            </tr>
        </tbody>
    </table>
</div>

Forms

<form>
    <!-- Text input -->
    <div class="mb-3">
        <label class="form-label required"><?= gettext('First Name') ?></label>
        <input type="text" class="form-control" name="firstName" required>
    </div>

    <!-- Select -->
    <div class="mb-3">
        <label class="form-label"><?= gettext('Classification') ?></label>
        <select class="form-select" name="classification">
            <option value=""><?= gettext('Select...') ?></option>
        </select>
    </div>

    <!-- Checkbox -->
    <div class="mb-3">
        <label class="form-check">
            <input class="form-check-input" type="checkbox" name="active">
            <span class="form-check-label"><?= gettext('Active member') ?></span>
        </label>
    </div>

    <!-- Submit -->
    <button type="submit" class="btn btn-primary">
        <?= gettext('Save') ?>
    </button>
</form>

Dark Mode

Dark mode is a per-user preference set in My Settings → Theme. It is handled entirely by Tabler's CSS variables — no special PHP logic is needed in templates. Use Tabler's semantic color tokens (e.g., text-muted, bg-body-secondary) rather than hardcoded hex colors so pages look correct in both light and dark modes.

<!-- ✅ Correct — uses semantic tokens, works in dark mode -->
<p class="text-muted">Secondary text</p>
<div class="bg-body-secondary p-3 rounded">...</div>

<!-- ❌ Avoid — hardcoded colors break in dark mode -->
<p style="color: #666;">Secondary text</p>
<div style="background: #f8f9fa;" class="p-3 rounded">...</div>

RTL Support

ChurchCRM supports RTL locales (Arabic, Hebrew, etc.) automatically. Tabler handles text direction via the dir="rtl" attribute on <html>. In templates, use Bootstrap 5 logical properties (me-*, ms-*, pe-*, ps-*, start, end) instead of directional ones (mr-*, ml-*, left, right) so layout mirrors correctly in RTL.


Layout Patterns

Standard page layout

<?php require SystemURLs::getDocumentRoot() . '/Include/Header.php'; ?>

<div class="container-xl">
    <div class="page-header d-print-none">
        <div class="row align-items-center">
            <div class="col">
                <h2 class="page-title"><?= gettext('Page Title') ?></h2>
            </div>
            <div class="col-auto ms-auto">
                <!-- page-level action button -->
                <a href="#" class="btn btn-primary">
                    <i class="ti ti-plus me-1"></i><?= gettext('Add New') ?>
                </a>
            </div>
        </div>
    </div>

    <div class="card">
        <div class="card-body">
            <!-- content -->
        </div>
    </div>
</div>

<?php require SystemURLs::getDocumentRoot() . '/Include/Footer.php'; ?>

Resources

🚀 Getting Started

docs.churchcrm.io for installation & setup


👥 For End Users

docs.churchcrm.io for user manuals


🔧 For Administrators

docs.churchcrm.io for admin manuals


👨‍💻 For Developers

Contributing to ChurchCRM


📚 Help & Reference

Clone this wiki locally