Skip to main content

patternfly_yew/components/
switch.rs

1//! Switch control
2use crate::ouia;
3use crate::prelude::{Icon, OuiaComponentType};
4use crate::utils::{Ouia, OuiaSafe};
5use web_tools::prelude::*;
6use yew::prelude::*;
7
8const OUIA: Ouia = ouia!("Switch");
9
10/// Properties for [`Switch`]
11#[derive(Clone, PartialEq, Properties)]
12pub struct SwitchProperties {
13    #[prop_or_default]
14    pub id: Option<String>,
15
16    #[prop_or_default]
17    pub checked: bool,
18
19    #[prop_or_default]
20    pub label: Option<String>,
21    #[prop_or_default]
22    pub label_off: Option<String>,
23    #[prop_or_default]
24    pub disabled: bool,
25
26    #[prop_or_default]
27    pub onchange: Callback<bool>,
28
29    #[prop_or_default]
30    pub aria_label: String,
31
32    /// OUIA Component id
33    #[prop_or_default]
34    pub ouia_id: Option<String>,
35    /// OUIA Component Type
36    #[prop_or(OUIA.component_type())]
37    pub ouia_type: OuiaComponentType,
38    /// OUIA Component Safe
39    #[prop_or(OuiaSafe::TRUE)]
40    pub ouia_safe: OuiaSafe,
41}
42
43/// Switch component
44///
45/// > A **switch** toggles the state of a setting (between on and off). Switches and checkboxes can often be used interchangeably, but the switch provides a more explicit, visible representation on a setting.
46///
47/// See: <https://www.patternfly.org/components/switch>
48///
49/// ## Properties
50///
51/// Defined by [`SwitchProperties`].
52#[function_component(Switch)]
53pub fn switch(props: &SwitchProperties) -> Html {
54    let checked = use_state(|| props.checked);
55
56    use_effect_with(
57        (props.checked, checked.setter()),
58        |(checked, checked_setter)| {
59            checked_setter.set(*checked);
60        },
61    );
62
63    let ouia_id = use_memo(props.ouia_id.clone(), |id| {
64        id.clone().unwrap_or(OUIA.generated_id())
65    });
66    let input_ref = use_node_ref();
67
68    let onchange = use_callback(
69        (input_ref.clone(), props.onchange.clone(), checked.setter()),
70        |_evt, (input_ref, onchange, checked_setter)| {
71            checked_setter.set(input_ref.checked());
72            onchange.emit(input_ref.checked())
73        },
74    );
75
76    let label = match (props.label.as_ref(), *checked) {
77        (Some(label), true) => html!(
78            <span class="pf-v6-c-switch__label">{label}</span>
79        ),
80        (Some(label), false) => {
81            let label = props.label_off.as_ref().unwrap_or(label);
82            html!(
83                <span class="pf-v6-c-switch__label">{label}</span>
84            )
85        }
86        (None, _) => html!(),
87    };
88
89    html! (
90        <label
91            class="pf-v6-c-switch"
92            for={props.id.clone()}
93            data-ouia-component-id={(*ouia_id).clone()}
94            data-ouia-component-type={props.ouia_type}
95            data-ouia-safe={props.ouia_safe}
96        >
97            <input
98                ref={input_ref.clone()}
99                class="pf-v6-c-switch__input"
100                type="checkbox"
101                id={props.id.clone()}
102                aria-label={props.aria_label.clone()}
103                checked={*checked}
104                disabled={props.disabled}
105                {onchange}
106            />
107            <span class="pf-v6-c-switch__toggle">
108                if props.label.is_none() {
109                    <span class="pf-v6-c-switch__toggle-icon">
110                        { Icon::Check }
111                    </span>
112                }
113            </span>
114            {label}
115        </label>
116    )
117}