<defs> + <use>
Content placed inside <defs> is parsed and stored by the browser but never painted directly. Think of it as a private template library sitting at the top of your SVG. To actually draw a piece of that library you stamp it onto the canvas with <use href="#id">.
This separation of definition and instantiation is the key to keeping SVG files small and consistent. Change the shape in <defs> once and every <use> instance updates automatically — the same principle behind CSS classes.
Defining a shape and instancing it
The example below defines a single hexagon inside <defs>, then stamps it out three times. Each <use> element can supply its own x/y offset and override fill — but the geometry comes entirely from the one definition.
The fill attribute on a <use> element feeds into the shadow DOM that the browser creates for each instance. Because fill is an inherited presentation attribute, a value set on the <use> wrapper is inherited by the content inside — overriding the definition's own fill. Properties that are not inherited (like stroke-width) would need a more targeted approach, such as CSS custom properties.
Resizing instances with width and height
When the referenced element is a <symbol> (covered next), you can resize instances by setting width and height on <use>. For plain shapes such as the hexagon above, the most reliable way to scale is with a transform="scale(…)" on the <use> element, because plain shapes have no viewBox to scale into.
<symbol> + <use> — icon systems
<symbol> is like <defs> but purpose-built for icons. A symbol carries its own viewBox, which means each instance can be given a width and height and the symbol's content will scale to fit — exactly the same way that a standalone SVG file scales. This is the native SVG equivalent of an image sprite.
In production, all your symbols live in a single hidden <svg> that you include once per page (or load as a separate .svg file and reference with <use href="sprite.svg#icon-id">). Every icon on the page then becomes a single lightweight element with no duplicated path data.
Three icons defined as symbols
The hidden <svg> below contains three symbols. They are invisible until referenced. Each <use> gives the icon a size via width/height and optionally overrides the color.
Notice that the icon paths use stroke="currentColor" and fill="currentColor" rather than hard-coded hex values. The color CSS property set on the <use> element flows down as currentColor, so you can theme an entire icon set just by changing one property — or by setting color in CSS with a class. This is the standard technique used by icon libraries like Heroicons and Phosphor.
How an external sprite sheet works
In a real project you would put all your <symbol> definitions in a single file, say icons.svg, and reference them across pages without any inline markup:
The browser downloads icons.svg once and caches it. All subsequent icon uses are free. Cross-origin references require the server to send a permissive Access-Control-Allow-Origin header, but on the same origin they always work.
<marker> — arrowheads and path decorations
A <marker> is a small graphic that is automatically painted at specific points along a path or line. The three attachment properties are:
marker-start— placed at the very first point of the path.marker-mid— placed at every intermediate point (between start and end).marker-end— placed at the very last point, typically used for arrowheads.
The key marker attributes:
markerWidth/markerHeight— the size of the marker's bounding box in marker units.refX/refY— the point within the marker that lines up with the path vertex. For an arrowhead you usually setrefXto the tip of the arrow.orient="auto"— rotates the marker so it always points along the path direction. Useorient="auto-start-reverse"onmarker-startto flip it automatically.markerUnits="strokeWidth"(default) — marker dimensions are multiples of the stroke width, so the arrowhead scales with the line thickness.
Simple arrowhead on a line
Define the arrowhead shape inside <defs><marker>, then apply it to a <line> or <path> via the marker-end attribute.
The refX="6" means "align the point 6 units along the marker's x-axis with the path endpoint." Since the arrowhead tip is drawn at x=8, setting refX to 6 leaves a small gap — the visible tip of the arrow aligns cleanly with the line end. Adjust refX if you notice the arrow overshooting or undershooting.
Both ends, and a curved path
You can apply different markers to start and end. Here a double-headed arrow labels a curved path segment, demonstrating marker-start with orient="auto-start-reverse" so both heads point outward.
The orient="auto-start-reverse" value on the start marker tells the browser to rotate the marker as normal for a marker-end but then flip it 180°. This means you can define the arrowhead shape pointing right once and reuse it on both ends without a separate "left-pointing" definition.
Dot markers at midpoints
Markers are not limited to arrowheads. Using marker-mid, you can place a decoration at every vertex of a polyline — useful for labeling data points on a chart or diagram.