owl-concept/menu-bundle

Bundle Symfony pour la navigation dynamique — sidebar repliable, topbar, breadcrumbs, groupes accordion, badges, icônes, filtrage par rôles, détection active automatique.

Maintainers

Package info

github.com/Jaecko/owl-menu-bundle

Type:symfony-bundle

pkg:composer/owl-concept/menu-bundle

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-03-06 15:29 UTC

This package is auto-updated.

Last update: 2026-05-06 15:50:39 UTC


README

PHP Symfony License

🇫🇷 Français

Bundle Symfony pour la navigation dynamique — sidebar repliable, topbar horizontale, breadcrumbs auto-générés, groupes accordion, badges, icônes, filtrage par rôles, détection active automatique.

Fonctionnalités

  • Sidebar repliable — largeur 260px → 60px (icônes seules) avec transition fluide
  • Topbar horizontale — alternative navbar avec dropdowns
  • Breadcrumbs auto-générés — fil d'Ariane basé sur la hiérarchie du menu
  • Groupes accordion — sous-menus pliables avec animation
  • Badges / Compteurs — notifications visuelles sur les items
  • Icônes — préfixe configurable (Bootstrap Icons, FontAwesome, etc.)
  • Filtrage par rôles — masque les items selon les rôles Symfony
  • Détection active automatique — highlight basé sur l'URL courante
  • Anti-flash — script inline lit localStorage avant le premier rendu
  • Responsive — burger menu sur mobile ≤ 768px
  • Variables CSS — fonctionne avec ou sans owl-theme-bundle
  • Zéro dépendance JS — vanilla JS, pattern IIFE

Installation

composer require owl-concept/menu-bundle

Configuration

# config/packages/owl_menu.yaml
owl_menu:
    css_class_prefix: 'owl-menu'          # Préfixe BEM
    collapse_storage: 'localStorage'       # localStorage | settings
    active_detection: 'auto'               # auto | manual
    icon_prefix: 'bi bi-'                  # Préfixe CSS des icônes

Utilisation

Créer un menu dans un contrôleur ou service

use OwlConcept\MenuBundle\Builder\MenuBuilder;

class AppController extends AbstractController
{
    public function index(MenuBuilder $menuBuilder): Response
    {
        $menu = $menuBuilder->create('sidebar')
            ->addItem('dashboard', 'Tableau de bord', '/dashboard', [
                'icon' => 'house',
            ])
            ->addGroup('crm', 'CRM', ['icon' => 'people'], function ($group) {
                $group->addItem('clients', 'Clients', '/clients', [
                          'badge' => 5,
                          'badge_color' => 'danger',
                      ])
                      ->addItem('contacts', 'Contacts', '/contacts');
            })
            ->addDivider()
            ->addItem('settings', 'Paramètres', '/settings', [
                'icon' => 'gear',
                'position' => 'bottom',
                'roles' => ['ROLE_ADMIN'],
            ])
            ->setCollapsible(true)
            ->setActiveAuto(true)
            ->build();

        return $this->render('base.html.twig', ['menu' => $menu]);
    }
}

Templates Twig

{# Sidebar #}
{% include '@OwlMenu/sidebar.html.twig' with { menu: menu } %}

{# Topbar (alternative) #}
{% include '@OwlMenu/topbar.html.twig' with { menu: menu } %}

{# Breadcrumb #}
{% include '@OwlMenu/breadcrumb.html.twig' with { menu: menu } %}

Fonctions Twig

{# Récupérer un menu enregistré par ID #}
{% set menu = owl_menu('sidebar') %}

{# Breadcrumb depuis l'ID #}
{% set crumbs = owl_menu_breadcrumb('sidebar') %}

{# Vérifier si un item est actif #}
{% if owl_menu_is_active('clients') %}...{% endif %}

{# Icône HTML #}
{{ owl_menu_icon('house') }}  {# → <i class="bi bi-house"></i> #}

{# Préfixe CSS #}
{{ owl_menu_prefix() }}  {# → owl-menu #}

Options des items

Option Type Défaut Description
icon string null Nom de l'icône (sans préfixe)
badge int|string null Texte ou compteur du badge
badge_color string null Couleur : danger, warning, success
roles string[] [] Rôles Symfony requis (OR)
position string default default ou bottom
target string null Attribut target du lien
css_class string null Classe CSS supplémentaire
divider_before bool false Séparateur avant l'item
divider_after bool false Séparateur après l'item

Détection active (scoring URL)

Le bundle compare l'URL courante avec chaque item :

URL courante Item /dashboard Item /clients Item /contacts
/dashboard 100 (exact) 0 0
/clients/123/edit 0 8 (prefix) 0
/contacts 0 0 100 (exact)

L'item avec le score le plus élevé est marqué actif, et son groupe parent est auto-déplié.

Intégrations optionnelles

  • owl-theme-bundle — les variables CSS var(--owl-*) sont automatiquement utilisées
  • owl-settings-bundlecollapse_storage: settings persiste l'état via DBAL

Assets

{# CSS #}
<link rel="stylesheet" href="{{ asset('bundles/owlmenu/css/owl-menu.css') }}">

{# JS (en fin de body) #}
<script src="{{ asset('bundles/owlmenu/js/owl-menu.js') }}"></script>

Installer les assets :

php bin/console assets:install public

API JavaScript

// Accéder à l'API
window.OwlMenu.init();  // Ré-initialiser (après AJAX)

// Écouter les événements
document.addEventListener('owl-menu:collapse', function(e) {
    console.log(e.detail.id, e.detail.collapsed);
});

document.addEventListener('owl-menu:mobile', function(e) {
    console.log(e.detail.id, e.detail.open);
});

🇬🇧 English

Symfony bundle for dynamic navigation — collapsible sidebar, horizontal topbar, auto-generated breadcrumbs, accordion groups, badges, icons, role-based filtering, automatic active detection.

Features

  • Collapsible sidebar — 260px → 60px (icons only) with smooth transition
  • Horizontal topbar — alternative navbar with dropdowns
  • Auto-generated breadcrumbs — breadcrumb trail based on menu hierarchy
  • Accordion groups — collapsible sub-menus with animation
  • Badges / Counters — visual notifications on items
  • Icons — configurable prefix (Bootstrap Icons, FontAwesome, etc.)
  • Role-based filtering — hides items based on Symfony roles
  • Automatic active detection — highlight based on current URL
  • Anti-flash — inline script reads localStorage before first paint
  • Responsive — burger menu on mobile ≤ 768px
  • CSS variables — works with or without owl-theme-bundle
  • Zero JS dependencies — vanilla JS, IIFE pattern

Installation

composer require owl-concept/menu-bundle

Configuration

# config/packages/owl_menu.yaml
owl_menu:
    css_class_prefix: 'owl-menu'          # BEM prefix
    collapse_storage: 'localStorage'       # localStorage | settings
    active_detection: 'auto'               # auto | manual
    icon_prefix: 'bi bi-'                  # Icon CSS prefix

Usage

Create a menu in a controller or service

use OwlConcept\MenuBundle\Builder\MenuBuilder;

class AppController extends AbstractController
{
    public function index(MenuBuilder $menuBuilder): Response
    {
        $menu = $menuBuilder->create('sidebar')
            ->addItem('dashboard', 'Dashboard', '/dashboard', [
                'icon' => 'house',
            ])
            ->addGroup('crm', 'CRM', ['icon' => 'people'], function ($group) {
                $group->addItem('clients', 'Clients', '/clients', [
                          'badge' => 5,
                          'badge_color' => 'danger',
                      ])
                      ->addItem('contacts', 'Contacts', '/contacts');
            })
            ->addDivider()
            ->addItem('settings', 'Settings', '/settings', [
                'icon' => 'gear',
                'position' => 'bottom',
                'roles' => ['ROLE_ADMIN'],
            ])
            ->setCollapsible(true)
            ->setActiveAuto(true)
            ->build();

        return $this->render('base.html.twig', ['menu' => $menu]);
    }
}

Twig Templates

{# Sidebar #}
{% include '@OwlMenu/sidebar.html.twig' with { menu: menu } %}

{# Topbar (alternative) #}
{% include '@OwlMenu/topbar.html.twig' with { menu: menu } %}

{# Breadcrumb #}
{% include '@OwlMenu/breadcrumb.html.twig' with { menu: menu } %}

Twig Functions

{# Get a registered menu by ID #}
{% set menu = owl_menu('sidebar') %}

{# Breadcrumb from ID #}
{% set crumbs = owl_menu_breadcrumb('sidebar') %}

{# Check if an item is active #}
{% if owl_menu_is_active('clients') %}...{% endif %}

{# Icon HTML #}
{{ owl_menu_icon('house') }}  {# → <i class="bi bi-house"></i> #}

{# CSS prefix #}
{{ owl_menu_prefix() }}  {# → owl-menu #}

Item Options

Option Type Default Description
icon string null Icon name (without prefix)
badge int|string null Badge text or counter
badge_color string null Color: danger, warning, success
roles string[] [] Required Symfony roles (OR logic)
position string default default or bottom
target string null Link target attribute
css_class string null Additional CSS class
divider_before bool false Divider before item
divider_after bool false Divider after item

Active Detection (URL scoring)

The bundle compares the current URL against each item:

Current URL Item /dashboard Item /clients Item /contacts
/dashboard 100 (exact) 0 0
/clients/123/edit 0 8 (prefix) 0
/contacts 0 0 100 (exact)

The item with the highest score is marked active, and its parent group is auto-expanded.

Optional Integrations

  • owl-theme-bundle — CSS variables var(--owl-*) are automatically used
  • owl-settings-bundlecollapse_storage: settings persists state via DBAL

Assets

{# CSS #}
<link rel="stylesheet" href="{{ asset('bundles/owlmenu/css/owl-menu.css') }}">

{# JS (at end of body) #}
<script src="{{ asset('bundles/owlmenu/js/owl-menu.js') }}"></script>

Install assets:

php bin/console assets:install public

JavaScript API

// Access the API
window.OwlMenu.init();  // Re-initialize (after AJAX)

// Listen to events
document.addEventListener('owl-menu:collapse', function(e) {
    console.log(e.detail.id, e.detail.collapsed);
});

document.addEventListener('owl-menu:mobile', function(e) {
    console.log(e.detail.id, e.detail.open);
});

License

Proprietary — All rights reserved.