diff --git a/doc/book/menu-configuration.rst b/doc/book/menu-configuration.rst
index 6fff0f99ad..9c9836655a 100644
--- a/doc/book/menu-configuration.rst
+++ b/doc/book/menu-configuration.rst
@@ -94,6 +94,26 @@ the ``icon`` option and leave it empty or set it to ``null``:
- { entity: 'Product', icon: '' }
# ...
+CSS Classes
+~~~~~~~~~~~
+
+Applications that need full customization, for example to display each menu item
+with a different color or style, can define the ``css_class`` option for one or
+more menu items:
+
+.. code-block:: yaml
+
+ easy_admin:
+ design:
+ menu:
+ - { entity: 'User', css_class: 'menu--user' }
+ - { entity: 'Product', css_class: 'menu--product text-bold text-center' }
+ - { entity: 'Category', css_class: 'default' }
+ # ...
+
+The CSS class is applied to the ```` element that wraps both the icon and
+the label of the menu item.
+
Targets
~~~~~~~
diff --git a/src/Configuration/MenuConfigPass.php b/src/Configuration/MenuConfigPass.php
index 916280415b..fd43ea51e3 100644
--- a/src/Configuration/MenuConfigPass.php
+++ b/src/Configuration/MenuConfigPass.php
@@ -86,6 +86,11 @@ private function normalizeMenuConfig(array $menuConfig, array $backendConfig, $p
$itemConfig['icon'] = 'fa-'.$itemConfig['icon'];
}
+ // normalize css_class configuration
+ if (!array_key_exists('css_class', $itemConfig)) {
+ $itemConfig['css_class'] = '';
+ }
+
// normalize submenu configuration (only for main menu items)
if (!isset($itemConfig['children']) && -1 === $parentItemIndex) {
$itemConfig['children'] = array();
diff --git a/src/Resources/views/default/menu.html.twig b/src/Resources/views/default/menu.html.twig
index 916df14631..7b77607b4e 100644
--- a/src/Resources/views/default/menu.html.twig
+++ b/src/Resources/views/default/menu.html.twig
@@ -18,7 +18,7 @@
{% set path = path(item.route, menu_params|merge(item.params)) %}
{% endif %}
-
+
{% if item.icon is not empty %}{% endif %}
{{ item.label|trans(domain = translation_domain) }}
{% if item.children|default([]) is not empty %}{% endif %}
diff --git a/tests/Controller/CustomMenuTest.php b/tests/Controller/CustomMenuTest.php
index 44c8fd4400..2ea354aa01 100644
--- a/tests/Controller/CustomMenuTest.php
+++ b/tests/Controller/CustomMenuTest.php
@@ -124,6 +124,41 @@ public function testMenuIcons()
);
}
+ public function testMenuCssClasses()
+ {
+ $crawler = $this->getBackendHomepage();
+
+ $this->assertSame(
+ 'label-custom-css-class',
+ $crawler->filter('.sidebar-menu li:contains("Products") a')->attr('class'),
+ 'First level label menu item with custom CSS class'
+ );
+
+ $this->assertSame(
+ 'entity-custom-css-class',
+ $crawler->filter('.sidebar-menu li:contains("Images") a')->attr('class'),
+ 'First level entity menu item with custom CSS class'
+ );
+
+ $this->assertSame(
+ '',
+ $crawler->filter('.sidebar-menu li:contains("Purchases") a')->attr('class'),
+ 'First level entity menu item without custom CSS class'
+ );
+
+ $this->assertSame(
+ 'route-custom-css-class',
+ $crawler->filter('.sidebar-menu li:contains("Custom Internal Route") a')->attr('class'),
+ 'First level route menu item with custom CSS class'
+ );
+
+ $this->assertSame(
+ 'children-custom-css-class',
+ $crawler->filter('.sidebar-menu .treeview-menu li:contains("Categories") a')->attr('class'),
+ 'Second level menu item with custom CSS class'
+ );
+ }
+
public function testMenuTargets()
{
$crawler = $this->getBackendHomepage();
diff --git a/tests/Fixtures/App/config/config_custom_menu.yml b/tests/Fixtures/App/config/config_custom_menu.yml
index 20773318a5..e8663eb998 100644
--- a/tests/Fixtures/App/config/config_custom_menu.yml
+++ b/tests/Fixtures/App/config/config_custom_menu.yml
@@ -9,13 +9,14 @@ easy_admin:
menu:
- label: 'Products'
icon: 'shopping-basket'
+ css_class: 'label-custom-css-class'
children:
- { entity: 'Product', icon: 'th-list', label: 'List Products', params: { sortField: 'createdAt' } }
- { entity: 'Product', label: 'Add Product', params: { action: 'new' } }
- { label: 'Additional Items' }
- - { entity: 'Category', label: 'Categories', default: true, icon: '' }
+ - { entity: 'Category', label: 'Categories', default: true, icon: '', css_class: 'children-custom-css-class' }
- { label: 'Absolute URL', url: 'https://github.com/javiereguiluz/EasyAdminBundle' }
- - { label: 'Images', entity: 'Image' }
+ - { label: 'Images', entity: 'Image', css_class: 'entity-custom-css-class' }
- { label: 'Purchases', entity: 'Purchase', icon: '', params: { sortField: 'deliveryDate', customParameter: 'customValue' } }
- { label: 'About EasyAdmin' }
- { label: 'Project Home', url: 'https://github.com/javiereguiluz/EasyAdminBundle', icon: 'home', target: '_blank' }
@@ -23,4 +24,4 @@ easy_admin:
- { label: 'Report Issues', url: 'https://github.com/javiereguiluz/EasyAdminBundle/issues', icon: 'github', target: 'arbitrary_value' }
- { label: 'Misc.' }
- { route: 'custom_route', label: 'Custom External Route', params: { custom_parameter: 'Lorem Ipsum' } }
- - { route: 'easyadmin', label: 'Custom Internal Route' }
+ - { route: 'easyadmin', label: 'Custom Internal Route', css_class: 'route-custom-css-class' }