Using SVG icons in ExtJs

tags: extjs svg icons

In this issue we will figure out how to use any SVG icons in ExtJs buttons. All icons will be combined to a single sprite that injected to index.html. Example uses Google Icons set.

ExtJs has several ways to add an icon on a button. Here are these properties:

  • iconCls + css class that defines background image
  • icon + path to icon that will be used in background property
  • glyph + font-based symbol, see docs…

Let’s add some SVG here.

Prepare SVG sprite

Let’s create SVG sprite that contains all needed icons in project. For this tutorial, I will use icons from https://design.google.com/icons/. But it can be any other SVG icons created in a vector-graphic software. I selected Save and Delete icons from the set:

Google Icons

Download SVG files of selected icons, e.g. Save icon will look like:

<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
    <path d="M0 0h24v24H0z" fill="none"/>
    <path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
</svg>

Then combine icons into a single SVG sprite, all paths of each icon should be into a separate symbol tag and has unique id:

<svg xmlns="http://www.w3.org/2000/svg" style="position:absolute;height:0;width:0;">
    <defs>
        <symbol viewBox="0 0 24 24" id="svg-icon-save">
            <path d="M0 0h24v24H0z" fill="none"/>
            <path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
        </symbol>
        <symbol viewBox="0 0 24 24" id="svg-icon-delete">
            <path d="M0 0h24v24H0V0z" fill="none"/>
            <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.13-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/>
            <path d="M0 0h24v24H0z" fill="none"/>
        </symbol>
    </defs>
</svg>

Include the sprite into index.html

For include our sprite into page just paste it before </body> tag:

<body>
    <!-- other stuff here-->

    <svg xmlns="http://www.w3.org/2000/svg" style="position:absolute;height:0;width:0;">
        <defs>
            <symbol viewBox="0 0 24 24" id="svg-icon-save">
                <path d="M0 0h24v24H0z" fill="none"/>
                <path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
            </symbol>
            <symbol viewBox="0 0 24 24" id="svg-icon-delete">
                <path d="M0 0h24v24H0V0z" fill="none"/>
                <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.13-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/>
                <path d="M0 0h24v24H0z" fill="none"/>
            </symbol>
        </defs>
    </svg>
</body>

SVG sprite should be hidden on a page, so position:absolute;height:0;width:0; style was applied here.

Override Button class

The next step is overriding Button class to support new button’s parameter iconSvg. Create a file %APP_FOLDER%/overrides/button/Button.js and copy this code into it:

// overrides/button/Button.js
Ext.define('Override.button.Button', {
    override: 'Ext.button.Button',

    // inject svg to icon template
    iconTpl: [
        '<span id="{id}-btnIconEl" data-ref="btnIconEl" role="presentation" unselectable="on" ',
            'class="{baseIconCls} {baseIconCls}-{ui} {iconCls} {glyphCls}{childElCls}" ',
            'style="',
                '<tpl if="iconUrl">background-image:url({iconUrl});</tpl>',
                '<tpl if="glyph && glyphFontFamily">font-family:{glyphFontFamily};</tpl>',
                '<tpl if="iconSvg">display: inline-block;</tpl>',
            '">',
            '<tpl if="glyph">&#{glyph};</tpl>',
            '<tpl if="iconCls || iconUrl">&#160;</tpl>',
            '<tpl if="iconSvg">', // new property
                '<svg class="svg-icon svg-icon-{iconSvg}"><use xlink:href="#svg-icon-{iconSvg}"></use></svg>',
            '</tpl>',
        '</span>'
    ].join(''),

    // extend template values
    getTemplateArgs: function () {
        var args = this.callParent();
        args.iconSvg = this.iconSvg;
        return args;
    }
});

Looks like a lot of changes, but actually here are two small things:

  • new property in template
'<tpl if="iconSvg">', // new property
    '<svg class="svg-icon svg-icon-{iconSvg}"><use xlink:href="#svg-icon-{iconSvg}"></use></svg>',
'</tpl>',
  • overrided getTemplateArgs function to add iconSvg parameter into template’s values object.

Add styles for new icons

Add CSS styles for the icons to an appropriate place, e.i. %APP_FOLDER%/sass/etc/svg-icons.scss:

.svg-icon {
  fill: #ffffff;
  width: 24px;
  height: 24px;
}

.svg-icon-save {
  margin: 0 1px 0 3px;
}

.svg-icon-delete {
  margin: 0 0 0 3px;
}

Import the new style file svg-icons.scss in %APP_FOLDER%/sass/etc/all.scss:

@import "svg-icons";

If you use a theme package, it will be the best place for the new svg-icons.scss file.

After all changes, do not forget to re-build the application.

Using the new icons with buttons

Now we are ready to use our new icons. Just add the iconSvg property into button configuration:

items: [{
    xtype: 'button',
    text: 'Save',
    iconSvg: 'save', // <--- here
    scale: 'medium'
}, {
    xtype: 'button',
    text: 'Delete',
    iconSvg: 'delete', // <--- and here
    scale: 'medium'
}]

Update a page and get the icons on buttons:

Buttons with Google Icons

There was a simplistic solution, that can be improved. You could add getter/setter functions for the new property to make it bindable. Instead of overriding you could use extended button class. For using in other components just add a similar solution to it, or place SVG icon template directly to component configuration. Injection sprite into index.html can be automated. All depends on a project.

Links

Thanks for reading. I will glad to get any feedback!

Comments: