[SalesForce] Can we use SVG icons outside those provided by SLDS

I have created an SVG Lightning component that takes 3 attributes, namely, "class","xlinkHref" and "areaHidden".

<aura:component >
  <aura:attribute name="class" type="String" description="CSS classname for the SVG element" />
  <aura:attribute name="xlinkHref" type="String" description="SLDS icon path. Ex: /assets/icons/utility-sprite/svg/symbols.svg#download" />
  <aura:attribute name="ariaHidden" type="String" default="false" description="aria-hidden true or false. defaults to true" />
</aura:component>

The renderer.js given below does the ground-work to render the SVG icon provided through xlinkHref attribute.

({
  render: function(component, helper) {
    //grab attributes from the component markup
    var classname = component.get("v.class");
    var xlinkhref = component.get("v.xlinkHref");
    var ariaHidden = component.get("v.ariaHidden");

    //return an svg element w/ the attributes
    var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute('class', classname);
    svg.setAttribute('aria-hidden', ariaHidden);
    svg.innerHTML = '<use xlink:href="'+xlinkhref+'"></use>';
    return svg;
  }
})

Here is the example use case:

<c:svg class="slds-icon" xlinkHref="/resource/SLDS100/assets/icons/standard-sprite/svg/symbols.svg#home" /> 

All this work fine, as long as I provide path to any icon within SLDS Sprite maps (Action, custom, standard, Utility). However, the list is not exhaustive. I'm looking for a "pause" icon and I couldn't find it in SLDS sprite maps.

I tried to use a pause SVG from here, saved it under static resources and in the xlinkHref parameter I used "/resources/name_of_the_static_resource_for_pause_icon". The icon didn't turn up on the UI.

Can anyone point out what's wrong?

Best Answer

In your component markup put the SVG inside an CDATA container and surround it with DIV giving an aura:id.

<div aura:id="svg_content">
<![CDATA[
    <svg width="120px" height="120px" viewBox="0 0 120 120" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
        <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
            <path d="M120,108 C120,114.6 114.6,120 108,120 L12,120 C5.4,120 0,114.6 0,108 L0,12 C0,5.4 5.4,0 12,0 L108,0 C114.6,0 120,5.4 120,12 L120,108 L120,108 Z" id="Shape" fill="#2A739E"/>
            <path d="M77.7383308,20 L61.1640113,20 L44.7300055,63.2000173 L56.0543288,63.2000173 L40,99.623291 L72.7458388,54.5871812 L60.907727,54.5871812 L77.7383308,20 Z" id="Path-1" fill="#FFFFFF"/>
        </g>
    </svg>
]]>
</div>

Then in the renderer.js for the component, override the afterRender method:

afterRender: function(component, helper) {
    this.superAfterRender();
    var svg = component.find("svg_content");
    var value = svg.getElement().innerText;
    value = value.replace("<![CDATA[", "").replace("]]>", "");
    svg.getElement().innerHTML = value;        
}

This is a workaround that works for any SVGs outside of those provided by SLDS.