10 releases
Uses new Rust 2024
| 0.5.7 | Apr 21, 2026 |
|---|---|
| 0.5.6 | Apr 10, 2026 |
| 0.5.2 | Mar 31, 2026 |
| 0.4.1 | Mar 20, 2026 |
| 0.3.3 | Mar 17, 2026 |
#91 in GUI
Used in 2 crates
1MB
22K
SLoC
native-theme
What it does
Cross-platform theme data model with 24 semantic color roles, 25 per-widget
themes, and 16 bundled TOML presets. Reads OS themes from KDE Plasma, GNOME
(via xdg-desktop-portal), macOS, and Windows, and produces a fully populated
ResolvedTheme any GUI toolkit can consume.
How it fits
Most apps don't depend on this crate directly — they use a framework connector like
native-theme-gpui or
native-theme-iced, which pull native-theme in
transitively. Depend on native-theme directly only if you are writing a new connector.
Quick start
Add the dependency:
cargo add native-theme
Read the live OS theme:
use native_theme::SystemTheme;
let sys = SystemTheme::from_system()?;
let active = sys.pick(sys.mode); // &ResolvedTheme
let accent = active.defaults.accent_color; // Rgba (fully populated)
let bg = active.defaults.background_color; // Rgba
# Ok::<(), native_theme::error::Error>(())
For OS readers, enable the native feature (or an individual kde / portal
/ macos / windows) — see Feature flags below. No features
are needed to use bundled presets.
Core concepts
-
Theme— sparse, TOML-shaped definition (fields areOption<T>). Load viaTheme::preset(…),Theme::from_toml(…), orTheme::from_file(…). -
ResolvedTheme— fully-populated variant where every field has a value. Safe to hand to UI code. -
ColorMode— theLight/Darkchoice passed when resolving. -
Preset — a named bundled theme. 16 ship today:
- Platform:
kde-breeze,adwaita,windows-11,macos-sonoma,material,ios - Community:
catppuccin-latte,catppuccin-frappe,catppuccin-macchiato,catppuccin-mocha,nord,dracula,gruvbox,solarized,tokyo-night,one-dark
Enumerate with
Theme::list_presets()orTheme::list_presets_for_platform(). - Platform:
Common recipes
Load a bundled preset
use native_theme::theme::{ColorMode, Theme};
let theme = Theme::preset("catppuccin-mocha")?;
let resolved = theme.resolve(ColorMode::Dark)?;
let accent = resolved.variant.defaults.accent_color; // Rgba
# Ok::<(), native_theme::error::Error>(())
theme.resolve(mode) returns a Resolved wrapper containing variant
(the ResolvedTheme) plus the effective icon-set and icon-theme metadata.
Layer user overrides on a preset
use native_theme::theme::Theme;
let mut theme = Theme::preset("nord")?;
let overrides = Theme::from_toml(r##"
name = "My Nord"
[light.defaults]
accent_color = "#ff6600"
"##)?;
theme.merge(&overrides);
# Ok::<(), native_theme::error::Error>(())
merge fills in only the fields present in the overlay; everything else stays
from the base preset.
Apply an overlay to the OS theme at runtime
use native_theme::{SystemTheme, theme::Theme};
let sys = SystemTheme::from_system()?;
let overlay = Theme::from_toml(r##"
[light.defaults]
accent_color = "#ff6600"
"##)?;
let customised = sys.with_overlay(&overlay)?;
# Ok::<(), native_theme::error::Error>(())
Cheap dark-mode poll
use native_theme::detect::system_is_dark;
if system_is_dark() {
// …
}
Cached, does not run the full theme-reader pipeline.
Icon sets
Semantic icon roles map to platform-appropriate glyphs via typed per-set loaders:
use native_theme::icons::{MaterialLoader, FreedesktopLoader};
use native_theme::theme::IconRole;
// Bundled set (no system dependencies).
let copy = MaterialLoader::new(IconRole::ActionCopy).load();
// System icon theme on Linux (reads the active theme, e.g. breeze-dark).
let sys = FreedesktopLoader::new(IconRole::ActionCopy)
.theme("breeze-dark")
.load();
Animated spinners respect the OS prefers-reduced-motion preference:
use native_theme::icons::MaterialLoader;
use native_theme::detect::prefers_reduced_motion;
if let Some(anim) = MaterialLoader::load_indicator() {
if prefers_reduced_motion() {
let _static_fallback = anim.first_frame();
} else {
// Play the animation — AnimatedIcon has Frames and Transform variants.
}
}
Connector crates provide toolkit playback helpers (see the native-theme-gpui
and native-theme-iced READMEs).
Feature flags
[dependencies]
native-theme = { version = "0.5", features = ["native"] }
native is a meta-feature enabling every OS reader for the current target
(kde + portal + macos + windows). Individual features:
| Feature | Role |
|---|---|
kde / portal / macos / windows |
Platform-specific theme readers |
linux |
Meta-feature: kde + portal |
watch |
Runtime theme-change notifications |
system-icons |
Linux freedesktop icon-theme lookups |
material-icons / lucide-icons |
Bundle those icon sets |
svg-rasterize |
Rasterize SVG icons to RGBA via resvg |
OS-specific dependencies are target-gated — native on macOS only pulls in
macOS-related deps.
Links
- API reference on docs.rs
- Connectors:
native-theme-gpui,native-theme-iced - Showcase examples
- CHANGELOG
License
Licensed under any of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be triple licensed as above, without any additional terms or conditions.
Dependencies
~1–50MB
~721K SLoC