A manifest-driven icon system for native Rust GUI applications: describe
your icon set once in TOML (local files, URLs, iconify.design ids, font
glyphs, mixed freely), get a typed Rust registry, a Slint component, and
a compile-time-checked icon! macro that hands your GUI framework its
native image type directly.
Most native Rust GUI apps hardcode include_bytes! per icon by hand - no
manifest, no shared registry, no compile-time check that a referenced
icon actually exists in the set. guicons gives you that single source of
truth, with codegen and a macro on top so referencing an icon is a
typed, checked operation instead of a bare file path.
- One manifest,
icons.gui.toml: family/variant/size axes,[link] includes = [...]to split across files,[providers.<name>]schemas (10+ built-in providers, with per-field.override). - Any source, mixed freely: local file, URL, iconify.design id (auto-fetched and cached offline), or a font glyph.
- Typed build-time codegen (
guicons-build): a Rust registry with per-family/size builder methods, and a matching SlintIconcomponent. guicons::icon!: resolves a selector against your manifest at compile time straight into your active GUI framework's native type (slint::Image, an icedHandle).- Slint integration out of the box, with a runnable example in
crates/guicons/examples/. - CLI (
guicons-cli):icons fetch/updatepopulates the offline iconify cache;icons add <iconify-id|file>adds an icon to your manifest in one command. - LSP (
guicons-lsp): completion, hover, goto-definition, find usages, rename, and diagnostics, with navigation betweenicons.gui.tomland your Rust code in both directions. - RustRover/IntelliJ plugin: a sidebar tool window showing your manifest's structure, with icon previews and a built-in iconify.design browser to search, preview, and insert a reference at the caret in one click.
# icons.gui.toml
[defaults]
root = "assets"
[providers.phosphor]
variants = ["thin", "light", "bold", "fill", "duotone"]
[link]
includes = ["icons/toolbar.gui.toml"]
[settings]
variants.filled = { file = "settings-filled.svg" }
variants.regular = { file = "settings-regular.svg" }
[docker]
file = "docker.svg"
[home]
iconify = "mdi:home"
[spinner]
glyph = "MyIconFont:U+E001"# icons/toolbar.gui.toml - split out via [link], same [defaults] root
[toolbar.16]
variants.filled = { file = "toolbar-16-filled.svg" }
[toolbar.24]
variants.filled = { file = "toolbar-24-filled.svg" }
variants.regular = { file = "toolbar-24-regular.svg" }// build.rs
fn main() {
guicons_build::IconBuild::auto()
.emit(guicons_build::Emit::Rust)
.emit(guicons_build::Emit::Slint)
.build();
}// lib.rs or main.rs
guicons::include_icons!();Most of the time you just want to hand an icon straight to your GUI
framework - guicons::icon! resolves a selector, checked against your
manifest at compile time, directly to whichever framework's native type
matches your enabled feature (slint or iced; plain IconData if
neither is enabled):
// with the `slint` feature enabled, this is already a `slint::Image`
my_component.set_icon(guicons::icon!(settings.filled));Use guicons::icon_data! instead if you always want the plain IconData,
regardless of which GUI feature is enabled.
Use guicons normally at runtime, and add guicons-build as a
build-dependencies entry when generating code from build.rs.
For the less common case where the family/variant is only known at
runtime (not a literal you can pass to icon!), or you need a
runtime-swappable IconKey (theming, hot-reload via IconResolver),
use the generated registry functions or guicons::icon_key! directly:
let key = icons::key_from_dynamic_family_variant("settings", None, Some("filled"));
let key = guicons::icon_key!(settings.filled); // icons::keys::SETTINGS_FILLEDThe generated icons.slint (from Emit::Slint above) exports an Icon
component that switches on a name property, plus one typed component
per icon (settings-filled → SettingsFilledIcon) - import either
from your own .slint files:
import { Icon, SettingsFilledIcon } from "icons.slint"; // resolved via an include path pointing at OUT_DIR
// Dynamic - runtime string match against `name`
Icon {
name: "settings-filled";
}
// Typed - one exported component per icon, checked at compile time
SettingsFilledIcon {}For icon data you don't already have as icon! output - e.g. resolved at
runtime through an IconResolver - guicons::slint converts IconData/
IconSource to a Slint Image, or to a (font_family, char) pair for
glyph sources. See examples/slint_icon.rs
for a complete, runnable example (cargo run -p guicons --example slint_icon --features slint).
guicons::iced gives you iced::widget::svg::Handle/image::Handle
directly from IconData/IconSource, plus the same glyph pair for
font-based icons. See examples/iced_icon.rs
for a complete, runnable example (cargo run -p guicons --example iced_icon --features iced).