backpack/theme-tabler
A modern Tabler-based admin theme for Backpack for Laravel. Replace the default look with a clean, responsive Bootstrap interface that works with your existing CRUD panels, fields, widgets, and dashboards—install via Composer, no code changes needed.
backpack/theme-tabler is a Backpack v6 theme, not a standalone UI kit. It swaps Backpack's default admin chrome for Tabler running on Bootstrap 5. It does not change CRUD behaviour, routes, fields, or operations — only the layout, components, sidebar, dashboard shell, and widget styling.
Requirements: Backpack v6 (backpack/backpack:^6), Laravel 9+, PHP 8.1+. Version 2.1.0 remains a minor release in the same major line, so an existing 2.0.x integration should upgrade without code changes.
Install:
composer require backpack/theme-tabler
For a fresh Backpack install, php artisan backpack:install will prompt for a theme and wire this one up. On an existing v6 app, Composer auto-discovery plus the theme's service provider is usually enough; confirm the package is discovered with:
php artisan package:discover
Look here first, in this order:
config/backpack/theme-tabler.php — the theme's published config. Read its comments; they are the authoritative list of knobs. As of 2.1.0 this includes the skin selector (see below), alongside layout, sidebar, and colour/class options depending on version.vendor/backpack/theme-tabler/resources/views/ — especially layouts/, inc/sidebar_content.blade.php, the dashboard view, widgets/, and (2.1.0+) any per-skin view/partial directories.app/Http/Controllers/Admin/DashboardController.php — the first place you will actually integrate with the theme.First real use case — pick a skin, then add a Tabler card to the dashboard:
// config/backpack/theme-tabler.php (2.1.0+)
// Set the skin key your install supports — read the published config for the exact
// option name and the list of bundled skins before guessing a value.
use Backpack\CRUD\app\Library\Widget;
public function index()
{
Widget::add([
'type' => 'card',
'wrapper' => ['class' => 'col-md-6'],
'content' => [
'title' => 'Welcome',
'body' => 'Your Tabler-themed dashboard is live.',
],
])->to('before_content');
return view('backpack::dashboard');
}
Then open /admin/dashboard. If the card renders inside a Tabler card/page wrapper, the theme is active. If the page looks like unstyled Bootstrap, the theme is not being resolved. If it looks Tabler-ish but with different colours/chrome than expected, check which skin is selected.
Your CrudController, fields, filters, and operations stay exactly as Backpack v6 documents them. The theme only affects rendered views. The practical work is therefore:
backpack_view(), not a hardcoded namespace;2.1.0 adds skins — alternate visual variants of the theme (palette/chrome presets) selected through configuration rather than by installing a different package. Treat them as the first thing to check when the admin UI doesn't look like the screenshots:
config/backpack/theme-tabler.php. Use the published config as the source of truth for the option name and the allowed values — do not copy a key from a blog post.--tblr-* overrides is not.config/backpack/theme-tabler.php published before 2.1.0, it will not have the new skin keys. Re-publish (or diff against the vendor config) to pick them up — otherwise you silently keep the default skin.Backpack registers the theme under the backpack.theme-tabler view namespace. Override any theme view by mirroring its path under:
resources/views/vendor/backpack/theme-tabler/
For example, to customise the sidebar, copy the package's inc/sidebar_content.blade.php to:
resources/views/vendor/backpack/theme-tabler/inc/sidebar_content.blade.php
Laravel's namespace override loads your file first. This is the primary extension point — never edit vendor/.
Where a skin ships its own variant of a view or partial, mirror the full relative path including the skin subdirectory if that is how the package lays it out; flattening the path produces an override that only applies to the default skin. Check the vendor tree for the exact structure before copying.
Use Backpack's theme-aware view helper so custom admin pages survive a future theme swap:
@extends(backpack_view('layouts.top_left'))
@section('content')
<div class="card">
<div class="card-body">Hello from a custom admin page.</div>
</div>
@endsection
Check the package's resources/views/layouts/ for the exact layout names available in your installed version. For custom routes, point them at a controller that returns one of these views and register the route in your Backpack route file as usual.
Do not edit the theme's compiled CSS. The layout exposes Blade stacks (after_styles, after_scripts, typically before_styles/before_scripts too). In a custom page, a dashboard view override, or your own layout override:
@push('after_styles')
<link rel="stylesheet" href="{{ asset('css/admin.css') }}">
@endpush
@push('after_scripts')
<script src="{{ asset('js/admin.js') }}"></script>
@endpush
Backpack v6 uses Basset for asset management. Use basset() where the theme does, and clear Basset's cache after asset changes:
php artisan basset:clear
php artisan view:clear
Backpack v6 widgets are added with Widget::add([...])->to('placement'). Safe placements that the theme layout renders are before_content and after_content; sidebar placements exist too, but verify them against your version's layout before relying on them.
The theme ships widget views for common Tabler blocks — typically card, alert, progress, chart, plus generic view and div. For anything custom, use the view type:
Widget::add([
'type' => 'view',
'view' => 'admin.widgets.revenue',
'data' => ['total' => $total],
])->to('before_content');
{{-- resources/views/admin/widgets/revenue.blade.php --}}
<div class="card">
<div class="card-body">
<div class="text-muted">Revenue</div>
<div class="h1 m-0">{{ $total }}</div>
</div>
</div>
This is the cleanest way to get Tabler styling without fighting the theme's widget schema.
Tabler is driven by CSS custom properties (--tblr-primary, --tblr-body-bg, etc.). Order of preference: theme config → skin → CSS variable override → selector overrides (last resort).
@push('after_styles')
<style>
:root {
--tblr-primary: #1f6feb;
}
</style>
@endpush
Tabler's dark mode is activated with data-bs-theme="dark" on <html> — set it through the theme's HTML attributes/classes config if available, otherwise through a small layout override. Do not use Bootstrap 4-era data-theme patterns. If a skin changes how dark mode is expressed, re-test toggling after the upgrade.
Any custom field view must be BS5-native. Typical v5→v6 translations:
| Backpack v5 / BS4 | Backpack v6 / BS5 |
|---|---|
form-group |
mb-3 |
custom-select |
form-select |
input-group-append / input-group-prepend |
plain input-group children |
data-toggle / data-target |
data-bs-toggle / data-bs-target |
is-invalid + invalid-feedback |
same, still valid |
btn-default |
btn-secondary / btn-outline-secondary |
Keep using old($field['name'], $field['value']) and $field['attributes'] as normal. Skins don't change any of this.
Override inc/sidebar_content.blade.php and write Tabler navigation markup:
<ul class="navbar-nav pt-lg-3">
<li class="nav-item {{ request()->is('admin/dashboard') ? 'active' : '' }}">
<a class="nav-link" href="{{ backpack_url('dashboard') }}">
<span class="nav-link-title">Dashboard</span>
</a>
</li>
</ul>
Use backpack_url() rather than hardcoded /admin paths.
form-group, custom-select, and data-toggle.config/backpack/theme-tabler.php against the vendor copy after upgrading, and remember config is cached.backpack.theme-tabler), while the override directory uses dashes (resources/views/vendor/backpack/theme-tabler/). A mismatch makes overrides silently fail — no error, just the vendor view still rendering.php artisan view:clear && php artisan config:clear && php artisan basset:clear. In cached environments, config/backpack/theme-tabler.php changes are invisible until config:cache is rebuilt.php artisan package:discover after Composer changes.before_content and after_content are safest; custom placement strings require you to add a matching section/stack in a layout override.backpack/backpack and backpack/theme-tabler together (^2.1 if you want skins), and read the theme's Composer constraints before upgrading Laravel or Backpack. 2.1.0 is additive, but a skin change is a visual change: re-check dashboards, sidebar, login, and any custom layouts after switching.backpack/base do not apply here. Port them to backpack/theme-tabler paths and rewrite BS4 markup as BS5.APP_DEBUG=true), php artisan route:list | grep admin for route sanity, browser devtools to confirm which asset/CSS is actually loaded, and temporarily @dump or add a Blade comment in an override to prove it is being used. When styling looks off after a release, check the computed --tblr-* variables to confirm which skin is live.config/backpack/theme-tabler.php), view namespace overrides, backpack_view() for custom pages, Widget::add()->to() with type => 'view' for arbitrary dashboard blocks, layout stacks (after_styles, after_scripts), and custom field views.public/vendor/backpack/theme-tabler (or the Basset-built cache) exists and is web-accessible. Re-run the theme's publish/install step if the theme's assets were never published — and re-publish after upgrading if the new skins ship additional stylesheets.How can I help you explore Laravel packages today?