Skip to main content

dioxus_tw_components/components/
radio.rs

1use dioxus::prelude::*;
2
3#[derive(Clone)]
4struct RadioGroupCtx {
5    value: Signal<String>,
6    default_value: Signal<String>,
7    onchange: EventHandler<MouseEvent>,
8}
9
10#[derive(Clone, PartialEq, Props)]
11pub struct RadioGroupProps {
12    #[props(extends = div, extends = GlobalAttributes)]
13    attributes: Vec<Attribute>,
14    children: Element,
15
16    #[props(optional)]
17    default_value: String,
18
19    #[props(optional)]
20    value: Signal<String>,
21
22    #[props(optional)]
23    onchange: EventHandler<MouseEvent>,
24}
25
26#[component]
27pub fn RadioGroup(mut props: RadioGroupProps) -> Element {
28    let mut default_value = use_signal(|| props.default_value.clone());
29
30    use_context_provider(|| RadioGroupCtx {
31        value: props.value,
32        default_value,
33        onchange: props.onchange,
34    });
35
36    // Sync default_value from prop when it changes.
37    // peek() avoids subscription; write only when different to prevent re-render loops.
38    if *default_value.peek() != props.default_value {
39        *default_value.write() = props.default_value.clone();
40    }
41
42    let default_classes = "radio";
43    crate::setup_class_attribute(&mut props.attributes, default_classes);
44
45    rsx! {
46        div { ..props.attributes, {props.children} }
47    }
48}
49
50#[derive(Clone, PartialEq, Props)]
51pub struct RadioItemProps {
52    #[props(extends = input, extends = GlobalAttributes)]
53    attributes: Vec<Attribute>,
54    value: String,
55}
56
57#[component]
58pub fn RadioItem(mut props: RadioItemProps) -> Element {
59    let mut state = use_context::<RadioGroupCtx>();
60
61    let default_classes = "radio-input";
62    crate::setup_class_attribute(&mut props.attributes, default_classes);
63
64    let value = props.value.clone();
65    let checked = use_memo(move || {
66        if state.value.read().is_empty() {
67            *state.default_value.read() == value
68        } else {
69            (state.value)() == value
70        }
71    });
72
73    rsx! {
74        input {
75            r#type: "radio",
76            checked,
77            onclick: move |event| {
78                state.value.set(props.value.clone());
79                state.onchange.call(event);
80            },
81            ..props.attributes,
82        }
83    }
84}