Here I am

home

A guide to SVG <use> elements

04 Jan 2014

SVG <use> elements allow you to duplicate and re-use graphical SVG elements including <g>, <svg> and <symbol> elements as well as other <use> elements. With them, you can craft SVG documents with a DRY kind of approach.

Below is an example of simple SVG in an HTML document. When written inline in HTML5, there is no need to specify the svg namespace xmlns="http://www.w3.org/2000/svg" or xlink namespace xmlns:xlink="http://www.w3.org/1999/xlink" attributes.

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <rect
        x="100" y="20"
        width="50" height="50"
        fill="#29e" />
    <rect
        x="250" y="30"
        width="50" height="50"
        fill="#29e" />
</svg>

Apart from the x/y attributes the two <rect>s are identical. So instead of repeating code, we can write out only one of the <rect>s and duplicate it with a <use> element which has a different position.

To do this, we must:

The result is two identical elements in the exact same position. To change the position of a <use> element, we can use the x and y attributes or the transform attribute.

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <rect id="original-rect"
        x="100" y="20"
        width="50" height="50"
        fill="#29e" />

    <use xlink:href="#original-rect" x="150" y="10" />
        <!-- x/y of the <use> element
             are added to x/y of the referenced <rect> -->
</svg>

The resulting image is identical to that of the previous example, but requires less code.

Improvements

The reference would be much more convenient to use if it's center were always at the coordinates of it's duplicates so that if you wanted a rectange centered at (200, 50) you would simply write:

<use xlink:href="#original-rect" x="200" y="50" />
<!-- or -->
<use xlink:href="#original-rect" transform="translate(200 50)" />
<!-- using `transform` to position the element
     makes combining animations a lot easier -->

We can do this by moving the reference element into a <defs> element and positioning it so that it center is at (0, 0). All elements in <defs> elements are not rendered unless they are referenced by another visible element.

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <!-- list resourses in a <defs> element -->
    <defs>
        <rect id="def-rect"
            x="-25" y="-25"
            width="50" height="50"
            fill="#29e" />
    </defs>

    <!-- reference resourses by ID in xlink:href attribute -->
    <use xlink:href="#def-rect" transform="translate(100 50)"/>
    <use xlink:href="#def-rect" transform="translate(200 50)"/>
    <use xlink:href="#def-rect" transform="translate(300 50)"/>
</svg>

Property Inheritance

If a property like fill, stroke, stroke-width, etc. isn't specidied in the original element, then it can be inherited from the <use> element as if it were a <g>. For example, we can't change the fill color of elements using #def-rect by setting fill of the <use> element (since the attribute is already set in the reference element) but we can set the stroke style since that wasn't set in #def-rect.

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <use xlink:href="#def-rect" transform="translate(100 50)"
        fill="red"
        stroke="black"/>
    <use xlink:href="#def-rect" transform="translate(200 50)"
        fill="red"
        stroke="black" stroke-width="8"/>
    <use xlink:href="#def-rect" transform="translate(300 50)"
        fill="red"
        stroke="black" stroke-width="8" stroke-linejoin="round"/>
</svg>

Animations

Animations that are applied to the reference element are also observed in the duplicates. (Note that SMIL animations are not supported by Internet Explorer.)

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <defs>
        <rect id="anim-rect"
            x="-25" y="-25"
            width="50" height="50"
            fill="#29e" >

            <animate
                attributeName="fill"
                values="#29e; #4e4; #f40; #29e"
                dur="6s"
                repeatCount="indefinite" />
        </rect>
    </defs>

    <use xlink:href="#anim-rect" transform="translate(100 50)"/>
    <use xlink:href="#anim-rect" transform="translate(200 50)"/>
    <use xlink:href="#anim-rect" transform="translate(300 50)"/>
</svg>

Animations can also be added to each <use> element.

<!-- enable javascript to view a demo -->
<svg viewBox="0 0 400 100">
    <use xlink:href="#anim-rect" transform="translate(100 50)">
        <animateTransform
            attributeName="transform" type="rotate"
            values="0 0 0; 360 0 0"
            additive="sum"
            dur="6s"
            repeatCount="indefinite" /> </use>

    <use xlink:href="#anim-rect" transform="translate(200 50)">
        <animateTransform
            attributeName="transform" type="scale"
            values="0.5; 1.5; 0.5"
            additive="sum"
            dur="3s"
            repeatCount="indefinite" /> </use>

    <use xlink:href="#anim-rect" transform="translate(300 50)">
        <animateTransform
            attributeName="transform" type="translate"
            values="-12.5 -12.5;
                     12.5 -12.5;
                     12.5  12.5;
                    -12.5  12.5;
                    -12.5 -12.5"
            additive="sum"
            dur="3s"
            repeatCount="indefinite" /> </use>
</svg>

Dynamic <use> with javscript

To create a <use> element with javascript, as with any SVGElement, we use document.createElementNS which takes an xml namespace URI and element nodeName strings.

var useElement =
    document.createElementNS('http://www.w3.org/2000/svg', 'use');

document.querySelector('svg').appendChild(useElement);

To set the xlink:href attribute, we use Element.setAttributeNS which takes the namespace, the attribute name and the attribute value. In this case, the namespace is xlink the URI of which is http://www.w3.org/1999/xlink.

useElement.setAttributeNS(
        'http://www.w3.org/1999/xlink', // xlink NS URI
        'href',                         // attribute (no 'xlink:')
        '#anim-rect');                  // value to set