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:
- give the first
<rect>
an ID then we - replace the second with a
<use>
and - give it an
xlink:href
attribute with a value of"#[reference element ID]"
.
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