Dark Mode

Register and switch light and dark themes at runtime in a GPUI application.

Rust
1herogpui::theme::toggle_light_dark(cx);

Registering both appearances

ThemeProvider::init(cx) registers the provider with light and dark, so both themes are available without extra setup. Initialize it before opening the first window; rendering a themed component before initialization panics. To boot into dark, start from the dark theme instead:

Rust
1gpui_platform::application().with_assets(HeroGpuiAssets).run(|cx: &mut App| {
2    ThemeProvider::init(cx); // registers light + dark
3    // or ThemeProvider::init_with(Theme::dark(), cx);
4    // ...open windows
5});

Every theme, including your own, is registered under an id. Activating one repaints every open window. Customization covers building one.

Toggling at runtime

toggle_light_dark(cx) switches between the light and dark defaults. Call it from a menu item, keybinding or gallery control. Every themed component re-renders on the next frame.

Try it live

The gallery (cargo run -p herogpui-gallery) has the toggle in its top bar, and HEROGPUI_THEME=dark boots it straight into dark.

Switching to a registered theme

use_theme(id, cx) activates one of the registered themes by id — "light", "dark", or a custom one you have registered. toggle_light_dark uses it to select the other default theme.

Setting a custom theme

set_theme(theme, cx) registers and activates a theme in one step — use it when the theme was built with Theme::builder and has not been registered yet.

Rust
1herogpui::theme::use_theme("dark", cx);
2// or
3herogpui::theme::set_theme(my_custom_dark_theme, cx);

Reading the active appearance

ActiveTheme exposes cx.is_dark_theme() for a boolean. The provider also keeps the active id if you need the name. Both update when a switch lands.

Rust
1if cx.is_dark_theme() {
2    // your own dark-mode branch
3}
4
5// or ask the provider for the active id: "light", "dark", or a custom one
6let id = herogpui::theme::ThemeProvider::get(cx).active_id().clone();

Reduced motion

The same provider holds the app-level reduced-motion preference, because GPUI does not surface the OS prefers-reduced-motion setting. Seed it at startup with HEROGPUI_REDUCE_MOTION=1, or override it at any time with theme::set_reduce_motion(bool, cx) / toggle_reduce_motion(cx) — the app-level equivalent of enabling a reduced-motion setting. Every animated component honours it through cx.reduce_motion() without caller opt-in.