Skip to main content

dioxus_docs_kit/components/
theme_toggle.rs

1use dioxus::prelude::*;
2use dioxus_free_icons::Icon;
3use dioxus_free_icons::icons::ld_icons::{LdMoon, LdSun};
4
5use super::docs_layout::CurrentTheme;
6use crate::registry::DocsRegistry;
7
8/// Light/dark theme toggle button.
9///
10/// Reads theme configuration from `DocsRegistry` context and current theme from
11/// a `Signal<String>` context (provided by `DocsLayout`).
12///
13/// Renders nothing if the registry has no `toggle_themes` configured.
14#[component]
15pub fn ThemeToggle() -> Element {
16    let registry = use_context::<&'static DocsRegistry>();
17
18    let toggle = match registry
19        .theme
20        .as_ref()
21        .and_then(|t| t.toggle_themes.as_ref())
22    {
23        Some(t) => t.clone(),
24        None => return rsx! {},
25    };
26
27    let storage_key = registry
28        .theme
29        .as_ref()
30        .map(|t| t.storage_key.clone())
31        .unwrap_or_default();
32
33    let CurrentTheme(mut current_theme) = use_context::<CurrentTheme>();
34
35    let (light, dark) = toggle;
36    let is_dark = current_theme() == dark;
37
38    rsx! {
39        button {
40            class: "btn btn-ghost btn-sm btn-square",
41            title: if is_dark { "Switch to light mode" } else { "Switch to dark mode" },
42            onclick: move |_| {
43                let new_theme = if (current_theme)() == dark { light.clone() } else { dark.clone() };
44                current_theme.set(new_theme.clone());
45                let key = storage_key.clone();
46                spawn(async move {
47                    let _ = document::eval(&format!(
48                        r#"document.documentElement.setAttribute('data-theme', '{new_theme}');
49                        try {{ localStorage.setItem('{key}', '{new_theme}'); }} catch(e) {{}}"#
50                    ));
51                });
52            },
53            if is_dark {
54                Icon { class: "size-5", icon: LdSun }
55            } else {
56                Icon { class: "size-5", icon: LdMoon }
57            }
58        }
59    }
60}