Icon Packs

Introduction

WIP. Image and font icons resolve through the default resolver on all platforms; SVG and animated icons run through the same callback path but are not yet covered by built-in helpers.

An icon pack is a named bag of icons that the framework looks up by name when it sees a Dom::create_icon("home") node (or an <icon> element). Registration happens once on AppConfig.icon_provider; the lookup runs before every layout pass and resolves the name to a StyledDom subtree (typically an <img> or a glyph in an icon font).

use azul::prelude::*;
let mut config = AppConfig::create(/* ... */);

// 1. Register a font-icon pack pointing at Material Icons.
let material = /* a FontRef built once at startup */;
config.icon_provider.register_font_icon(
    "material".into(),
    "home".into(),
    material.clone(),
    "\u{e88a}".into(),
);
config.icon_provider.register_font_icon(
    "material".into(),
    "settings".into(),
    material,
    "\u{e8b8}".into(),
);

// 2. Register an image-icon pack for app-specific icons.
config.icon_provider.register_image_icon(
    "app".into(),
    "logo".into(),
    image_ref,
);

// 3. Use it in a Dom.
let dom = Dom::create_div().with_children(vec![
    Dom::create_icon("home".into()),
    Dom::create_icon("logo".into()),
].into());

How lookup works

Icons are stored on IconProviderHandle as a nested map of pack to icon-name to data. Lookup walks the packs in registration order and takes the first match. Pack names mostly exist for namespacing and bulk unregistration, not for selection.

Methods on IconProviderHandle:

  • register_icon(pack, name, data). Adds or overwrites an icon with arbitrary data.
  • register_font_icon(pack, name, font, char). Adds a font-glyph icon.
  • register_image_icon(pack, name, image). Adds an image icon.
  • unregister_icon(pack, name). Removes a single icon.
  • unregister_pack(pack). Removes every icon in a pack.
  • set_resolver(callback). Replaces the resolver for the whole provider.

Icon names are case-insensitive: registering "Home" and looking up "home" resolve to the same entry.

The resolver callback

The resolver turns a registered icon plus the original <icon> node into a StyledDom. The signature is IconResolverCallbackType:

extern "C" fn(
    icon_data: OptionRefAny,         // the data you registered, or None
    original_icon_dom: &StyledDom,   // the <icon> node with its inline styles
    system_style: &SystemStyle,      // current theme, accent, accessibility flags
) -> StyledDom;

The default resolver handles font icons (registered via register_font_icon) and image icons (via register_image_icon) out of the box. For anything else (SVG, animated, vector) write your own resolver and pass it to IconProviderHandle::with_resolver(my_callback) or IconProviderHandle::set_resolver(my_callback). The callback sees SystemStyle, so you can produce a different DOM for dark mode, a high-contrast variant, or a reduced-motion fallback.

System-style integration

The default resolver copies a curated subset of CSS properties from the original <icon> node onto the resolved DOM and filters based on SystemStyle. The IconStyleOptions type controls per-icon behaviour through three fields:

  • inherit_text_color makes the icon adopt the cascaded color.
  • prefer_grayscale drops explicit colour and adds a grayscale filter to image icons.
  • tint_color overrides the icon's fill with a single colour.

The cascade still runs as normal. A with_css("color: red;") on the <icon> node beats the system style.

Naming conventions

A pack is identified by its name string. The framework reserves no names, but the convention is:

  • app: your application's first-party icons.
  • material, phosphor, lucide, ...: third-party icon fonts.
  • os: anything you load from a platform icon theme (Windows shell imageres.dll, macOS NSImage, GNOME icon-theme.cache).

When two packs ship the same icon name, the first registered wins. Register your app pack last if you want app icons to override third-party ones.

Recipes

Toolbar with mixed packs

A toolbar mixing app and material icons

Themed icon button

use azul::prelude::*;
let _ = Dom::create_button("Settings", SmallAriaInfo::label("Settings"))
    .with_children(vec![Dom::create_icon("settings".into())].into())
    .with_css("
        display: inline-flex; gap: 6px; padding: 6px 12px;
        background: system:button-face;
        color: system:button-text;
        @theme dark { color: system:accent; }
    ");

The @theme dark rule changes the cascaded color, which the default font-icon resolver picks up when inherit_text_color is set.

Disabling and overriding

A few escape hatches:

  • IconProviderHandle::set_resolver(custom) swaps the whole resolver for one provider.
  • IconProviderHandle::unregister_pack("material".into()) removes every icon in a pack. Useful for „skin packs“ you load and unload at runtime.

End-user ricing of icons (replacing material/home with a user-chosen SVG without recompiling) is on the road map alongside the existing AZ_RICING CSS hook described in System Themes.

Coming Up Next

  • Images — Loading raster images and CSS backgrounds
  • Built-in Widgets — Built-in widgets and how to write your own
  • Layout — Overview of the layout solver

Back to guide index