dioxus_tw_components/components/
checkbox.rs1use crate::components::icon::*;
2use dioxus::prelude::*;
3
4#[derive(Clone, PartialEq, Props)]
5pub struct CheckboxProps {
6 #[props(extends = button, extends = GlobalAttributes)]
7 attributes: Vec<Attribute>,
8
9 #[props(optional)]
10 default_checked: bool,
11
12 #[props(optional)]
13 checked: Signal<bool>,
14
15 #[props(optional)]
17 onchange: Callback<bool, bool>,
18}
19
20#[component]
21pub fn Checkbox(mut props: CheckboxProps) -> Element {
22 let default_classes = "checkbox";
23 crate::setup_class_attribute(&mut props.attributes, default_classes);
24
25 let mut checked = use_signal(|| props.default_checked);
26
27 if *checked.peek() != props.default_checked {
30 *checked.write() = props.default_checked;
31 }
32
33 let id = crate::use_unique_id();
34 let id_clone = id.clone();
35
36 use_effect(move || {
42 let checked = *checked.read();
43 let js = document::eval(
44 r#"
45 let id = await dioxus.recv();
46 let action = await dioxus.recv();
47 let input = document.getElementById(id);
48
49 switch(action) {
50 case "checked":
51 input.checked = true;
52 input.indeterminate = false;
53 break;
54 case "unchecked":
55 input.checked = false;
56 input.indeterminate = false;
57 break;
58 }
59 "#,
60 );
61
62 let _ = js.send(id_clone.clone());
63 let _ = js.send(if checked { "checked" } else { "unchecked" });
64 });
65
66 rsx! {
67 button {
68 type: "button",
69 role: "checkbox",
70 "data-checked": if *checked.read() { "checked" } else { "unchecked" },
71 onclick: move |event| {
72 let new_checked = !checked();
73 checked.set(new_checked);
74 props.checked.set(new_checked);
75 if props.onchange.call(new_checked) {
76 event.stop_propagation();
77 }
78 },
79
80 onkeydown: move |e| {
82 if e.key() == Key::Enter {
83 e.prevent_default();
84 }
85 },
86 ..props.attributes,
87 span { class: "checkbox-indicator",
88 if *checked.read() {
89 Icon {
90 icon: Icons::Check
91 }
92 }
93 }
94 }
95 input {
96 id,
97 type: "checkbox",
98 aria_hidden: "true",
99 tabindex: "-1",
100 position: "absolute",
101 pointer_events: "none",
102 opacity: "0",
103 margin: "0",
104 transform: "translateX(-100%)",
105 }
106 }
107}