Magento 2 Admin – Changing Icon for Top Level Menu Items

adminimagemagento2menu

Is there a standard, framework supported way to add a new Icon to a Magento 2 top level Menu item?

When you add a new top level Menu Item to Magento 2's backend, you end up with a generic hexagon as the icon.

enter image description here

Is there an officially supported way to add a custom icon here? The <li/> tag has an id element, so I can think of an infinite number of ways to jam an icon in there via CSS. What I'm interested in here is how core Magento modules do it — i.e., what's The Right and True Way™ to add an icon.

Update: Re: Duplicates — I'm trying to avoid a solution like the one outlined here. i.e. all that does is jam some additional, unstructured CSS rules into a module in order to add an image. At minimum, Magento's own rules (seem to?) use a structured _menu.css file to style those icons. I'm operating from the point of view that there's a structured way to do this, and what I'm looking for is that structure, not another "this happens to work now but might break in the future because it doesn't follow the implicit design of the core system".

Best Answer

As of Magento 2.0.5, I don't think there is a structured way to do this.

Core Magento modules do it like this:

  • top menu items are added via menu.xml files
  • the CSS class is generated via the following code where $menuId is the id attribute of the menu item:

    $itemName = substr($menuId, strrpos($menuId, '::') + 2);
    $itemClass = "item-" . str_replace('_', '-', strtolower($itemName));
    
  • this CSS class is then being used in the app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less . For instance:

    .item-marketing {
        > a {
            &:before {
                @_menu-item-dashboard__size: 2rem;
                content: @icon-promotions__content;
                font-size: @_menu-item-dashboard__size;
                padding-top: @menu-item-icon__height - @_menu-item-dashboard__size;
             }
        }
    }
    
  • The icon itself it set via the content attribute that uses a less variable. In the example above, the less variable is @icon-promotions_content and is declared under app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less :

    @icon-promotions__content: '\e609';
    
  • The \e609 is an unicode entry then used in the app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg file (generated by IcoMoon btw) to generate the corresponding glyph:

    <glyph unicode="&#xe609;" glyph-name="promotions" horiz-adv-x="1170" d="M59.153 425.818l164.053-38.141v303.902l-164.053-38.141v-227.621zM1122.198 900.847l-837.712-194.959v-335.978l140.328-376.832 151.712 57.45-104.049 279.113 649.668-151.18v722.385z" />
    

I reckon the main problem is that the menu.xml does not handle such thing as an icon attribute, you can see it by looking at the app/code/Magento/Backend/etc/menu.xsd:

    <xs:attribute name="id" type="typeId" use="required" />
    <xs:attribute name="title" type="typeTitle" use="required" />
    <xs:attribute name="module" type="typeModule" use="required" />
    <xs:attribute name="sortOrder" type="xs:int" use="optional" />
    <xs:attribute name="action" type="typeAction" use="optional" />
    <xs:attribute name="parent" type="typeId" use="optional" />
    <xs:attribute name="toolTip" type="typeTitle" use="optional" />
    <xs:attribute name="resource" type="typeResource" use="required" />
    <xs:attribute name="dependsOnModule" type="typeModule" use="optional" />
    <xs:attribute name="dependsOnConfig" type="typeDependsConfig" use="optional" />
Related Topic