How to Use Topcoat’s Iconify Integration for Vendoring Icons

Enable the icon-iconify feature in both runtime and build dependencies, stage your desired icon sets via BuildConfig in build.rs, then import them using iconify::include! or iconify_icon! to embed thousands of SVG icons as compile-time constants.

The tokio-rs/topcoat framework provides first-class support for the Iconify ecosystem, allowing you to vendor any open-source icon set directly into your Rust binary. By leveraging the Iconify integration for vendoring icons, you eliminate runtime network requests and ship offline-capable, style-aware SVG components. The workflow downloads JSON definitions during compilation and exposes them as type-safe IconData constants ready for the icon component.

Enable the Feature in Cargo.toml

To access the Iconify tooling, you must activate the icon-iconify feature for both the runtime crate (to render icons) and the build crate (to stage icon sets).

Add the following to your Cargo.toml:

[dependencies]
topcoat = { version = "0.5", features = ["icon-iconify"] }

[build-dependencies]
topcoat = { version = "0.5", default-features = false, features = ["icon-iconify"] }

The runtime dependency enables the iconify module re-exported in [crates/topcoat/src/icon.rs](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat/src/icon.rs), while the build dependency compiles the staging logic defined in [crates/topcoat-icon/src/iconify/config.rs](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat-icon/src/iconify/config.rs).

Stage Icon Sets with build.rs

Create a build.rs file in your project root to download and cache the icon JSON files. The BuildConfig API lets you specify which sets to stage, where to cache them, and which versions to pin.

// build.rs
#[cfg(feature = "icon-iconify")]
fn main() {
    topcoat::icon::iconify::BuildConfig::new()
        .icon_set("feather")          // Stage the Feather icon set
        .stage()
        .expect("Failed to stage Iconify set");
}

#[cfg(not(feature = "icon-iconify"))]
fn main() {}

The first build downloads feather.json from the Iconify CDN and stores it in the default cache directory (or your configured path). Subsequent builds reuse the cached copy, supporting fully offline builds once the files are vendored. For version pinning or custom cache locations, see the configuration options below.

Import Icons into Your Application

Once staged, you can expose icons in your source code using one of two macros. Both resolve at compile time to IconData structs defined in the framework's icon system.

Using iconify::include! for Full Sets

The include! macro generates a Rust module containing one constant per icon in the set. This is ideal when you reference many icons from the same set.

use topcoat::icon::{icon, iconify};

// Creates a `feather` module with constants like `TRASH_2`, `ARROW_LEFT`, etc.
iconify::include!("feather");

async fn render(cx: &Cx) -> Result {
    view! {
        // Access via generated constant
        icon(data: feather::TRASH_2, label: "Delete")
    }
}

Using iconify_icon! for Single Icons

For one-off usage, the iconify_icon! macro expands a "set:name" string directly into an IconData constant without generating a module.

use topcoat::icon::{icon, iconify};

const TRASH: IconData = iconify::iconify_icon!("feather:trash-2");

view! {
    icon(data: TRASH, label: "Delete")
}

This approach is documented in [crates/topcoat-icon/macro/docs/iconify_icon.md](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat-icon/macro/docs/iconify_icon.md) and produces identical bytecode to the module-based approach.

Configure Caching and Version Pinning

The BuildConfig struct in [crates/topcoat-icon/src/iconify/config.rs](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat-icon/src/iconify/config.rs) exposes additional methods to control vendoring behavior.

Custom cache directory:

topcoat::icon::iconify::BuildConfig::new()
    .cache_dir("assets/icons")    // Store JSON files in your project tree
    .icon_set("feather")
    .stage()
    .unwrap();

Pin a specific version:

topcoat::icon::iconify::BuildConfig::new()
    .icon_set_version("feather", "1.0.0")  // Pin to npm-style version tag
    .icon_set("feather")
    .stage()
    .unwrap();

These options allow you to commit vendored icon files to version control, ensuring reproducible builds even if the upstream Iconify CDN is unavailable.

Summary

  • Enable the icon-iconify feature in both [dependencies] and [build-dependencies] in Cargo.toml.
  • Stage icon sets by calling BuildConfig::new().icon_set("name").stage() inside build.rs.
  • Import staged icons via iconify::include!("<set>") to generate a module of constants, or use iconify_icon!("<set>:<name>") for single icons.
  • Render the resulting IconData constants with the icon component in your views.
  • Cache downloaded JSON files locally or vendor them into your repository for offline builds.

Frequently Asked Questions

Do I need internet access for every build?

No. The BuildConfig::stage() method downloads icons only when the cache is missing or the requested version changes. Once cached, builds proceed offline. You can also check the cached JSON files into your repository using the cache_dir configuration to eliminate network dependencies entirely.

How do I pin a specific icon set version?

Call icon_set_version("<set>", "<tag>") on your BuildConfig instance before invoking stage(). This records the version in the cache key and ensures reproducible builds across environments, as implemented in [crates/topcoat-icon/src/iconify/config.rs](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat-icon/src/iconify/config.rs).

What is the difference between iconify::include! and iconify_icon!?

iconify::include!("<set>") generates a Rust module containing every icon in the set as a named constant (e.g., feather::TRASH_2), suitable for heavy usage of a specific set. iconify_icon!("<set>:<name>") expands a single string literal into an IconData constant inline, which is preferable for occasional usage or when minimizing binary size by avoiding unused icon definitions.

Where can I see a working example?

The repository provides two canonical examples: [examples/icon/src/main.rs](https://github.com/tokio-rs/topcoat/blob/main/examples/icon/src/main.rs) demonstrates basic include! usage, while [examples/ui/src/main.rs](https://github.com/tokio-rs/topcoat/blob/main/examples/ui/src/main.rs) and its accompanying [build.rs](https://github.com/tokio-rs/topcoat/blob/main/examples/ui/build.rs) show a full application staging multiple sets and rendering them within styled components.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →