JavaScript SVG Path Buttons


May 04, 2015

SVG can get a little cumbersome to write. Consider this SVG markup for a cloud shaped button wrapped in an anchor tag:

<a href="" class="btn">
    <span class="fallback-text">Cloud Button</span>
    <svg preserveAspectRatio="xMidYMin meet" viewBox="0 0 180 120" class="svg-button">
        <defs>
            <linearGradient id="redGradient" x2="0%" y2="100%">
                <stop offset="0%" stop-color="#f08578"></stop>
                <stop offset="100%" stop-color="#ec6252"></stop>
            </linearGradient>
        </defs>
        <path d="M162.658,74.635c0,16.55-13.52,31.07-28.93,31.07h-104.8c-15.41,0-28.93-14.52-28.93-31.07s13.52-31.07,28.93-31.07 c0.27,0,0.53,0.04,0.79,0.08c0.25,0.03,0.51,0.07,0.77,0.09l2.02,0.17l0.59-1.97c3.68-12.26,14.64-20.5,27.27-20.5 c1.48,0,3.04,0.14,4.76,0.44l1.75,0.3l0.86-1.57c7-12.71,20.24-20.6,34.55-20.6c21.81,0,39.56,18.01,39.56,40.16 c0,0.9-0.04,1.78-0.1,2.66l-0.12,1.93l1.78,0.65C154.568,49.445,162.658,61.745,162.658,74.635z" transform="translate(8, 5)"></path>
        <text x="50%" y="70%" text-anchor="middle">Cloud Button</text>
    </svg>
</a>

If I need to provide a fallback for non svg-capable browsers this will show up as a regular text button. All I would need to do is test if the browser supports svg and if it does, remove the fallback-text.

var supportsSVG = function() {
    return !!document.createElementNS && !!document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect;
};
if (supportsSVG) {
    // remove fallback text
}

What I want is a script to replace all the buttons on a page with a svg and a path variable I can change. This makes it very easy to drop in to each project and change the path to the appropriate value.

I start with the shape path variable:

var btn_shape_path = 'M162.658,74.635c0,16.55-13.52,31.07-28.93,31.07h-104.8c-15.41,0-28.93-14.52-28.93-31.07s13.52-31.07,28.93-31.07 c0.27,0,0.53,0.04,0.79,0.08c0.25,0.03,0.51,0.07,0.77,0.09l2.02,0.17l0.59-1.97c3.68-12.26,14.64-20.5,27.27-20.5 c1.48,0,3.04,0.14,4.76,0.44l1.75,0.3l0.86-1.57c7-12.71,20.24-20.6,34.55-20.6c21.81,0,39.56,18.01,39.56,40.16 c0,0.9-0.04,1.78-0.1,2.66l-0.12,1.93l1.78,0.65C154.568,49.445,162.658,61.745,162.658,74.635z';

I then store up all the buttons on the page:

var btns = document.getElementsByClassName("btn");

I need to create a function that adds the svg element and appropriate attributes inside the anchors:

var addSVG = function(btns, i) {
    var btn_text, defs, gradient, stop1, stop2, svgBtn, svgDoc, text, textNode, texts;
    texts = btns.getElementsByClassName('fallback-text')[0];
    svgDoc = document.createElementNS('http://www.w3.org/2000/svg', "svg");
    svgDoc.setAttributeNS(null, "preserveAspectRatio", 'xMidYMin meet');
    svgDoc.setAttributeNS(null, "viewBox", '0 0 180 120');
    svgDoc.setAttributeNS(null, "class", 'svg-button');
    svgBtn = document.createElementNS('http://www.w3.org/2000/svg', "path");
    svgBtn.setAttributeNS(null, "d", btn_shape_path);
    svgBtn.setAttribute('transform', 'translate(8, 5)');
    text = document.createElementNS('http://www.w3.org/2000/svg', "text");
    text.setAttributeNS(null, "x", '50%');
    text.setAttributeNS(null, "y", '70%');
    text.setAttributeNS(null, "text-anchor", 'middle');
    btns.appendChild(svgDoc);
    svgDoc.appendChild(svgBtn);
    texts.setAttribute("style", "display:none;");
    btn_text = texts.childNodes[0].nodeValue;
    textNode = document.createTextNode(btn_text);
    btns.appendChild(svgDoc);
    svgDoc.appendChild(svgBtn);
    svgDoc.appendChild(text);
    return text.appendChild(textNode);
};

Now I want to iterate over each button on the page and run the function:

[].forEach.call(btns, addSVG);

Now I can use this piece of code when I need buttons of any shape. I put a working example on CodePen:

See the Pen Cloud SVG Button w/ fallback by Jason Weaver (@indyplanets) on CodePen.

Latest Thoughts

Thanks for stopping by!