Skip to main content
go-swarm-icons
On this page

Sprite Sheets

Cut duplicate markup on a page by sharing repeated icons through symbol-based sprite sheets.

When the same icon appears multiple times on a page, each inline <svg> duplicates the full markup. Sprite sheets replace those duplicates with lightweight <use> references to a shared symbol definition, cutting page weight.

How sprites work

Instead of embedding the full SVG markup for each icon, render a lightweight <svg><use href="#i-lucide-home"></use></svg> reference. At the end of the page, inject a hidden sprite sheet containing one <symbol> per unique icon. The browser resolves the <use> references to the symbols in the sheet.

Setup

Go
import swarmicons "github.com/frostybee/go-swarm-icons"
sc := swarmicons.NewSpriteCollector()

NewSpriteCollector returns a ready-to-use collector. It is thread-safe and can be shared across concurrent render passes.

Register symbols

Call Register for each icon that should be available in the sprite sheet:

Go
import swarmicons "github.com/frostybee/go-swarm-icons"
sc := swarmicons.NewSpriteCollector()
icon, _ := manager.Get("lucide:home")
sc.Register("i-lucide-home", icon.Content(), "0 0 24 24")
icon, _ = manager.Get("lucide:star")
sc.Register("i-lucide-star", icon.Content(), "0 0 24 24")

The id parameter should follow the "i-{prefix}-{name}" convention.

Generate the sprite sheet

After rendering page HTML with <use href="#i-..."> references, pass the page content to SpriteSheet:

Go
import swarmicons "github.com/frostybee/go-swarm-icons"
pageHTML := []byte(`<html><body>
<svg><use href="#i-lucide-home"></use></svg>
<svg><use href="#i-lucide-star"></use></svg>
<svg><use href="#i-lucide-home"></use></svg>
</body></html>`)
sheet := sc.SpriteSheet(pageHTML)

SpriteSheet scans the page HTML for <use href="#i-..."> references, matches them against registered symbols, and returns a hidden <svg> element containing one <symbol> per unique referenced icon. Symbols are sorted by ID. Duplicate references produce only one <symbol>.

The returned markup looks like:

HTML
<svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden">
<symbol id="i-lucide-home" viewBox="0 0 24 24">...</symbol>
<symbol id="i-lucide-star" viewBox="0 0 24 24">...</symbol>
</svg>

SpriteSheet returns nil if no matching references are found in the page HTML.

ID namespacing

When a symbol is registered, internal SVG references (id, url(#...), href="#...") in the body are automatically suffixed to prevent collisions. For an id of "i-lucide-star", the suffix is "lucide-star" (the id with the "i-" prefix stripped).

For example, a body containing id="g" and url(#g) becomes id="g-lucide-star" and url(#g-lucide-star). This prevents two symbols from sharing the same internal reference IDs.

Reuse across pages

Call Reset() between pages to clear all registered symbols:

Go
sc.Reset()

Full example: SSG pipeline

Go
import (
"bytes"
"fmt"
swarmicons "github.com/frostybee/go-swarm-icons"
"github.com/frostybee/go-swarm-icons/lucide"
)
func main() {
manager := swarmicons.Default("lucide", lucide.Provider())
sc := swarmicons.NewSpriteCollector()
// Register the icons needed for this page
for _, name := range []string{"home", "star", "search"} {
icon, err := manager.Get(name)
if err != nil {
continue
}
_, _, w, h := icon.ViewBox()
vb := fmt.Sprintf("0 0 %d %d", w, h)
sc.Register(fmt.Sprintf("i-lucide-%s", name), icon.Content(), vb)
}
// Render page HTML with <use> references
var page bytes.Buffer
page.WriteString(`<nav>`)
page.WriteString(`<svg><use href="#i-lucide-home"></use></svg>`)
page.WriteString(`<svg><use href="#i-lucide-search"></use></svg>`)
page.WriteString(`</nav>`)
// Generate and inject the sprite sheet
sheet := sc.SpriteSheet(page.Bytes())
if sheet != nil {
page.Write(sheet)
}
fmt.Println(page.String())
// Reset for the next page
sc.Reset()
}

See also

Edit this page

Last updated: