Repeating Pattern with SVGs

Published on 01/02/2025


It turns out that SVG has a built-in mechanism to build repeating patterns that virtually cost nothing performance-wise, and it is awesome. Check it out:

1<svg width="690" height="136" xmlns="http://www.w3.org/2000/svg">
2 <pattern id="tilePattern" width="20" height="20" patternUnits="userSpaceOnUse">
3 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-axe">
4 <path d="m14 12-8.5 8.5a2.12 2.12 0 1 1-3-3L11 9"/>
5 <path d="M15 13 9 7l4-4 6 6h3a8 8 0 0 1-7 7z"/>
6 </svg>
7 </pattern>
8 <rect width="100%" height="100%" fill="url(#tilePattern)" />
9</svg>

In both JavaScript and Rust (considering GPUI), a common approach would be to use an array and map/iterate over it to draw an arbitrary number of icons until the design looks good. While this is certainly a valid way to go, it has the obvious performance drawback of adding a large number of repeated elements to the render/DOM.

SVG, however, has this functionality just there, built-in through the pattern tag. This tag can be passed as a URL in the fill attribute of the <rect> container, providing a much simpler solution. And if you combine that with a mask and linear gradient, you can create a super common fading-off pattern effect, without probably sacrificing virtually nothing in performance.

1<svg width="690" height="136" xmlns="http://www.w3.org/2000/svg">
2 <defs>
3 <pattern id="tilePattern" width="20" height="20" patternUnits="userSpaceOnUse">
4 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-axe">
5 <path d="m14 12-8.5 8.5a2.12 2.12 0 1 1-3-3L11 9"/>
6 <path d="M15 13 9 7l4-4 6 6h3a8 8 0 0 1-7 7z"/>
7 </svg>
8 </pattern>
9 <linearGradient id="fade" y2="1" x2="0">
10 <stop offset="0" stop-color="white" stop-opacity=".24"/>
11 <stop offset="1" stop-color="white" stop-opacity="0"/>
12 </linearGradient>
13 <mask id="fadeMask" maskContentUnits="objectBoundingBox">
14 <rect width="1" height="1" fill="url(#fade)"/>
15 </mask>
16 </defs>
17 <rect width="100%" height="100%" fill="url(#tilePattern)" mask="url(#fadeMask)"/>
18</svg>

Huge thanks to Agus for showing me this!