Icons

Lucide and Simple Icons with hugolify-theme-icons module

hugolify-theme-icons

Icons are a module of their own, hugolify-theme-icons. It renders Lucide for UI and content icons, and Simple Icons for brands.

The module is opt-in: a project that does not import it renders no icons. It ships no framework CSS and completes hugolify-theme-design-system, which bundles no icon of its own.

Not compatible with hugolify-theme-bootstrap

For now the module targets hugolify-theme-design-system only. hugolify-theme-bootstrap comes with its own icons — the Bootstrap Icons webfont — and both define a .icon class: importing the two together makes them collide.
hugolify-theme-icons on GitHub

Install

/config/_default/module.yaml

imports:
  - path: github.com/hugolify/hugolify-theme/v2
  - path: github.com/hugolify/hugolify-theme-design-system # styling module
  - path: github.com/hugolify/hugolify-theme-icons # icons

The module imports Lucide and Simple Icons as Hugo modules and mounts them on role-based paths (assets/icons/ui/, assets/icons/brands/), so swapping an icon set is a one-line change and no icon file is committed to your project.

Requires Hugo >= 0.128.0 (templates.Defer).

Usage

{{ partial "icon" "map-pin" }}      {{/* UI icon — Lucide name, as-is */}}
{{ partial "icon" "brand:github" }} {{/* brand icon — Simple Icons */}}

The name is the filename: there is no mapping table and no alias layer. Browse the Lucide icon list to find a name.

The rendered DOM is a single element, no inline SVG:

<i class="icon icon-map-pin" aria-hidden="true"></i>

Approach

Icons are rendered via CSS mask-image from inline SVG data-URIs. No icon font, no SVG sprite, no request per icon.

.icon {
  background-color: var(--icon-color, currentColor);
  display: inline-block;
  height: var(--icon-size, 1em);
  mask: var(--icon-glyph) center / contain no-repeat;
  vertical-align: -0.125em;
  width: var(--icon-size, 1em);
}

Each icon only differs by its --icon-glyph. The SVG is used as an alpha mask, so its own colors are irrelevant: the icon inherits the current text color via currentColor and scales with the font size.

Size and color are overridden with the two custom properties:

.main-menu .icon {
  --icon-color: var(--color-brand);
  --icon-size: var(--size-24);
}

Brand icons render monochrome — the norm for social rows. A colored logo needs an inline SVG instead of a mask.

Build

There is no project-side build step and no Node script. The subset ships natively:

  1. partial "icon" registers each name used during the render.
  2. After the full render, templates.Defer resolves the union of those names.
  3. One stylesheet is emitted (minified and fingerprinted in production) with the base .icon rule plus one --icon-glyph per icon actually used.

Nothing to run, and nothing to commit: there is no yarn build:icons step as with the Bootstrap Icons font, and no generated font file in the project.

An unknown name logs a build warning and renders nothing — the default glyph is an empty SVG, so a missing icon is invisible rather than a solid square.

Missing brands

Some brands are dropped by both Simple Icons and Lucide. The module ships curated SVGs in its own assets/icons/brands/, and local assets take precedence over the imported modules — so you can add a missing brand in your project at the same path:

assets/
└── icons/
    └── brands/
        └── linkedin.svg