If the application renders Markdown (a blog, a wiki, a documentation site), the Goldmark extension lets content authors embed icons inline with :icon[prefix:name] syntax, with no Go code in the templates and no manual SVG markup.
Install
The Goldmark extension is in a separate submodule:
go get github.com/frostybee/go-swarm-icons/goldmark@latestThis module depends on the core module and github.com/yuin/goldmark.
Register the extension
Create an IconManager, then pass it to the extension when configuring Goldmark:
import ( "bytes" "fmt" swarmicons "github.com/frostybee/go-swarm-icons" swarmgoldmark "github.com/frostybee/go-swarm-icons/goldmark" "github.com/frostybee/go-swarm-icons/lucide" "github.com/yuin/goldmark")func main() { manager := swarmicons.Default("lucide", lucide.Provider()) ext := &swarmgoldmark.Extension{ Manager: manager, SilentOnMissing: true, } md := goldmark.New(goldmark.WithExtensions(ext)) input := []byte("Click the :icon[lucide:home] icon to go home.") var buf bytes.Buffer if err := md.Convert(input, &buf); err != nil { panic(err) } fmt.Println(buf.String())}Inline syntax
The parser recognizes the pattern :icon[...] in Markdown source text. Everything between the brackets is parsed as an icon name followed by optional attributes.
Basic usage
:icon[lucide:home]Bare name (default prefix)
If the manager has a default prefix set, the prefix can be omitted:
:icon[home]This resolves as manager.Get("home"), which uses the default prefix.
With attributes
Attributes follow the icon name, separated by spaces. Values can be double-quoted, single-quoted, or unquoted:
:icon[lucide:star size="24" class="gold"]:icon[lucide:star size='24' class='gold']:icon[lucide:star size=24]Multiple icons on one line
:icon[lucide:home] and :icon[lucide:star]Both icons render independently.
Transform vs. pass-through attributes
Attributes split into two groups based on the key name:
Transform attributes
These are applied via fluent Icon methods after the icon is resolved:
| Attribute | Fluent method | Example |
|---|---|---|
size |
icon.Size(int) |
size="24" |
rotate |
icon.Rotate(float64) |
rotate="45" |
flip |
icon.Flip(string) |
flip="h" |
opacity |
icon.Opacity(float64) |
opacity="0.5" |
title |
icon.Title(string) |
title="Home" |
Transforms are applied in this order: size, rotate, flip, opacity, title.
Pass-through attributes
All other attributes (class, id, width, data-*, etc.) are passed to manager.Get() as caller-level attributes (layer 5 in the attribute merge). They follow the same merge rules as any other caller attributes.
:icon[lucide:home class="icon-blue" id="nav-home"]Missing icons
SilentOnMissing: true
When an icon is not found, the extension renders an HTML comment instead of returning an error:
<!-- SwarmIcons: Icon "lucide:missing" not found -->The rest of the Markdown document continues to render normally.
SilentOnMissing: false (default)
Full example
import ( "bytes" "fmt" swarmicons "github.com/frostybee/go-swarm-icons" swarmgoldmark "github.com/frostybee/go-swarm-icons/goldmark" "github.com/frostybee/go-swarm-icons/lucide" "github.com/yuin/goldmark")func main() { manager, _ := swarmicons.NewConfig(). AddProvider("lucide", lucide.Provider()). DefaultPrefix("lucide"). DefaultAttributes(map[string]string{ "stroke": "currentColor", "stroke-width": "2", "fill": "none", }). Build() ext := &swarmgoldmark.Extension{ Manager: manager, SilentOnMissing: true, } md := goldmark.New(goldmark.WithExtensions(ext)) input := []byte(`# WelcomeClick :icon[home] to return.Rate this: :icon[star size="16" class="gold" rotate="45"]`) var buf bytes.Buffer if err := md.Convert(input, &buf); err != nil { panic(err) } fmt.Println(buf.String())}The output contains the <h1> heading, paragraph text with the inline <svg> for "home", and a second paragraph with a rotated, gold-classed star icon.
See also
- Goldmark Extension API reference: full extension type, parser syntax, and renderer behavior
- Core Concepts: providers, prefixes, and attribute layers that apply to Goldmark-rendered icons