Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tabler Bundle Laravel Package

kevinpapst/tabler-bundle

Symfony bundle integrating the Tabler.io admin template, with Twig helpers, vertical and horizontal layouts, security pages, event-driven menus, a context helper, and translations—speeding up backend development on Bootstrap 5.

View on GitHub
Deep Wiki
Context7

Getting Started

The bundle is a Symfony theme package, not an app generator: it gives you Tabler's layouts, Twig components and navbar widgets, and expects you to feed them from your own services. Install is four steps and no more:

composer require kevinpapst/tabler-bundle
cp vendor/kevinpapst/tabler-bundle/config/packages/tabler.yaml config/packages/
// config/bundles.php
return [
    // ...
    KevinPapst\TablerBundle\TablerBundle::class => ['all' => true],
];

Then read vendor/kevinpapst/tabler-bundle/docs/index.md in order — it is short and split by topic (layout, menu, notifications, tasks, ThemeContext, one file per component). Do that before writing any Twig. Also clone TablerBundle-Demo: it is the fastest way to see a working dashboard, security screens and every component in context, and it doubles as a smoke test for how your asset pipeline should look.

Where to look first:

  1. config/packages/tabler.yaml — short; mostly route names for the user dropdown (login/logout/profile), asset/cache-busting flags, and icon defaults. Dump the full reference with bin/console config:dump-reference tabler.
  2. bin/console debug:twig --filter=tabler — lists the bundle's functions/filters.
  3. The templates themselves under vendor/kevinpapst/tabler-bundle/templates/ — they are plain Twig and are the real documentation for block names and embed arguments.
  4. bin/console debug:event-dispatcher — shows the Tabler menu/tasks/notifications events, which is where most of your integration work happens.

First use case (30 minutes): a read-only dashboard behind an existing firewall.

{# templates/dashboard/index.html.twig #}
{% extends '@Tabler/layout-vertical.html.twig' %}

{% block page_title %}Dashboard{% endblock %}

{% block page_actions %}
    <a href="{{ path('app_orders_index') }}" class="btn btn-primary">All orders</a>
{% endblock %}

{% block page_content %}
    <div class="row row-cards">
        <div class="col-md-4">
            {% embed '@Tabler/embeds/card.html.twig' with {title: 'Open orders'} %}
                {% block body %}{{ openCount }}{% endblock %}
            {% endembed %}
        </div>
    </div>
{% endblock %}

Keep page_content as your default extension point; page_wrapper, page_title and page_actions cover the rest (the wrapper blocks were added specifically for layout flexibility, so prefer them over copying the layout).

Implementation Patterns

One base template, everything else inherits. Create templates/base.html.twig that extends @Tabler/layout-vertical.html.twig (or layout-horizontal.html.twig) and add your own javascripts/stylesheets blocks plus global flash rendering there. Every page then extends your base, so a future bundle upgrade touches one file. Do the same for auth screens by extending the security layout rather than hand-rolling a login page.

Menus are event-driven, so no template edits per page. Register a subscriber once and add/remove items based on the current user's roles:

final class MenuSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [MenuEvent::class => 'onMenu'];
    }

    public function onMenu(MenuEvent $event): void
    {
        $menu = $event->getMenu();
        // illustrative shape: identifier, label, route, icon — confirm exact
        // builder/constructor arguments in docs/menu.md before copying
        $menu->add(new MenuItem('app_orders', 'Orders', 'app_orders_index', 'fa-solid fa-shopping-cart'));

        if ($this->security->isGranted('ROLE_ADMIN')) {
            $menu->add(new MenuItem('app_admin', 'Administration', 'app_admin_index', 'fa-solid fa-cog'));
        }
    }
}

Use the generated navbar-menu-<identifier> CSS classes (and the disabled / parent item options) for styling and sub-menus instead of overriding navbar templates. Same pattern for TasksEvent and the notification event: implement the bundle's notification interface in a small value object, and convert from your domain entities in the subscriber.

ThemeContext is your per-user "preferences" hook. Instead of duplicating layouts, inject the context into a kernel.request listener (after security) and apply stored user settings — layout, theme/colour mode, compactness. That is precisely the intended use case, and it keeps the choice out of every controller.

Lean on embeds/macros rather than writing markup. Cards, alerts, modals, accordions, dropdowns, timelines, progress bars, avatars and status badges all ship as @Tabler/embeds/* or macros. The daily loop is: open the matching embed file, copy its {% block %} names and with {...} keys from the file itself (block names differ per component), then fill in your data. This is what makes upgrades cheap — the release history shows template file renames (snake_case → kebab-case in 2.0) and class changes, so copied markup ages badly while embeds keep working.

Forms: Tabler is Bootstrap 5, so use Symfony's Bootstrap 5 form theme rather than any bundle-specific one; then your form_row output matches the theme's spacing out of the box.

Gotchas and Tips

  • The bundle pins Tabler, not the other way round. 2.4.x explicitly caps Tabler at 1.4 and is not compatible with Tabler 1.5. If you also npm install @tabler/core (or import the bundle's shipped assets), pin the npm version to match or you get subtly broken dropdowns/modals with no error message. Upgrade Tabler only when a bundle release does.
  • 2.x had real BC breaks. Follow UPGRADING.md: url → href on menu/notification options, snake_case → kebab-case option names, notification interfaces merged, progress-bar deprecations, and the bundle extension switched from prepend to build when attaching config. Anything you copied from a 1.x blog post or tutorial is suspect.
  • Font Awesome 5 → 6 happened in 1.1.0 (flagged as a possible BC break). Old fa fa-* classes may render blank; use fa-solid/fa-regular and verify against your icons config.
  • Notifications and tasks run on every request. The dropdowns are populated by event subscribers fired from the layout, so a naive repository query there will hit the DB on every page — including your own admin pages. Cache the counts (short TTL or a request-scoped memo) or gate the subscribers on the current route.
  • Modal blur effect causes performance problems on some workstations; 1.2.1 added a config switch to disable all modal effects. If users report lag when opening modals, check that flag before blaming your JS.
  • Prefer blocks and embeds over template overrides, and if you must override, use templates/bundles/TablerBundle/.... Templates changed shape across releases; a fork of the navbar is the most common reason people get stuck on an old version.
  • Route naming is config, not code. tabler_logout was deprecated in 1.4.2, and login/logout/profile links are configured in tabler.yaml. Point the config at your own route names rather than creating aliases to satisfy the bundle.
  • Twig deprecation churn is high (whitespace control, ??, spaceless removal, Twig 3.15 fixes). Keep twig/twig current and treat deprecation notices from @Tabler templates as upgrade signals, not noise.
  • Translation: built-in labels use the bundle's own domain with ~20 locales; your menu labels need their own domain/parameters passed on the item. Adding a locale is a Weblate contribution upstream, not a local override.
  • Maturity check: 133 stars, zero known dependents, effectively one maintainer. Pin "kevinpapst/tabler-bundle": "^2.4", read each release note before bumping minor versions, and budget an hour for the Symfony/PHP constraint hop — it has moved from Symfony 6→8 and PHP 8.1→8.5 support incrementally, and each step is a small migration.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk