Structuring, Grouping & Reusing
The larger your SVG file becomes, the harder it is to navigate. If you are drawing a complex illustration or creating an icon system, just throwing <path> after <path> is a bad idea.
In this lesson, we will look at the DRY (Don't Repeat Yourself) principle in SVG: how to group elements, create templates and reuse them without duplicating code.
1. The <g> tag: Grouping
The <g> (group) tag is the equivalent of a <div> in HTML or a "Folder" in graphics editors. It does not render anything by itself, but it combines nested elements.
Why you need it:
- Code organization: Logical separation (e.g.,
<g id="head">,<g id="arm">). - Mass transformation: You can move, rotate, or scale the entire group at once.
- Style inheritance: Attributes set for a group (e.g.,
fillorstroke) are applied to all nested elements (unless they have their own).
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- "Face" group: all elements inside will be red and shifted -->
<g id="face" fill="crimson" transform="translate(50, 50)">
<!-- Eyes (color is inherited from the group) -->
<circle cx="20" cy="20" r="10" />
<circle cx="80" cy="20" r="10" />
<!-- Mouth (override the color to white) -->
<rect x="20" y="60" width="60" height="10" fill="white" />
</g>
</svg>
2. The <defs> tag: Resource warehouse
<defs> (definitions) is a special area for storing objects. Everything inside <defs> is not automatically displayed on the canvas. This is a "warehouse" of templates, gradients, filters, or shapes that we plan to use later.
This is the basis for optimization: you define a complex object once, and then just refer to it.
<svg width="0" height="0">
<defs>
<!-- This circle is not visible until we call it -->
<circle id="my-template" cx="10" cy="10" r="10" fill="teal" />
</defs>
</svg>
3. The <use> tag: Cloning
The <use> tag gets an object from <defs> (or any other place by id) and renders a copy of it in the right place.
Advantages:
- Reduced file size (the shape code is not duplicated).
- A single source of truth (if you change the shape in
<defs>, all copies change).
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<circle id="coin" r="20" fill="gold" stroke="orange" stroke-width="2" />
</defs>
<!-- Use the coin 3 times in different places -->
<use href="#coin" x="50" y="50" />
<use href="#coin" x="150" y="50" />
<!-- You can add a transformation to a copy -->
<use href="#coin" x="250" y="50" transform="scale(0.8)" />
</svg>
Note: In older code examples, you may see xlink:href. In modern SVG, it is enough to write just href.
4. The <symbol> tag: The gold standard for icons
<symbol> is an advanced version of a group, created specifically for reuse.
Main differences from <g> and <defs>:
- Like
<defs>, the content of<symbol>is not displayed by itself. - Killer feature:
<symbol>has its ownviewBoxattribute.
This allows you to create SVG sprites (icon systems). No matter how the icon is drawn inside the symbol, you can insert it via <use> and give it any size (width and height), and it will fit perfectly thanks to its viewBox.
SVG sprite example
<svg style="display: none;">
<!-- "Home" icon definition -->
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</symbol>
<!-- "Settings" icon definition -->
<symbol id="icon-settings" viewBox="0 0 24 24">
<path d="M19.14 12.94c.04-.3.06-.61.06-.94... (long path) ..."/>
</symbol>
</svg>
Usage on the page
<!-- Large home icon -->
<svg class="icon"><use href="#icon-home" width="50" height="50"/></svg>
<!-- Small settings icon -->
<svg class="icon"><use href="#icon-settings" width="20" height="20"/></svg>
5. Shadow DOM and styling problems
When you use <use>, the browser creates a Shadow DOM. This means that the copy of the element is isolated from the rest of the page.
Problem:
You cannot use CSS to access the internals of a clone.
For example, this CSS will not work to change the color of a path inside <use>:
/* Will not work */
use path {
fill: blue;
}
Solution 1: Inheritance
Styles set on the <use> tag itself are inherited into the Shadow DOM.
For this to work, there should be no fill attribute inside the original symbol (or it should be currentColor).
Source:
<symbol id="star" viewBox="0 0 24 24">
<!-- Remove fill="black", set fill="currentColor" or remove it altogether -->
<path d="..." fill="currentColor" />
</symbol>
Usage:
<svg class="icon-red"><use href="#star" /></svg>
<svg class="icon-blue"><use href="#star" /></svg>
CSS:
.icon-red { color: red; } /* currentColor will take this value */
.icon-blue { fill: blue; } /* Or so */
Solution 2: CSS Variables
CSS variables (Custom Properties) penetrate the Shadow DOM boundary.
<symbol id="robot">
<rect fill="var(--main-color, black)" />
</symbol>
svg { --main-color: purple; }
Summary
<g>- for grouping parts of a single drawing (move together, paint together).<defs>- for storing gradients and masks.<symbol>+<use>- the standard for icon systems. Allows you to control theviewBoxof each icon separately.- Use
currentColorin icon paths to easily recolor them via CSS when using<use>.