tablo_ui/components/primitives/switch.rs
1// SYNC: topcoat-ui-registry@0.12.0 sha256:226d9269f1d87bdf43cbddbcea450eb2a11944032dc307c656f8bf806a3d5932 — do not hand-edit. Sync via `cargo xtask sync-topcoat-ui` (ADR-0007).
2use topcoat::{
3 Result,
4 context::Cx,
5 view::{Attributes, StaticClass, View, class, component, view},
6};
7
8/// Classes for the checkbox input that forms the switch track.
9const SWITCH: StaticClass = class!(
10 "peer h-4.5 w-8 shrink-0 appearance-none rounded-full",
11 "bg-foreground/20 shadow-xs transition-colors outline-none checked:bg-primary",
12 "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
13 "focus-visible:ring-offset-background disabled:pointer-events-none",
14);
15
16/// Classes that position the thumb at either end of the track according to the checked
17/// state.
18const THUMB: StaticClass = class!(
19 "pointer-events-none absolute top-1/2 left-0.5 size-3.5 -translate-y-1/2",
20 "rounded-full bg-background shadow-xs transition-transform peer-checked:translate-x-3.5",
21);
22
23/// An on/off control for a setting.
24///
25/// Uses a native checkbox with the `switch` role. Pass `checked` in `attrs` for the
26/// initial state. Classes apply to the wrapper, while other attributes and event
27/// handlers go on the `<input>`.
28///
29/// ```ignore
30/// view! {
31/// <div class="flex items-center gap-2">
32/// let airplane_mode = element_id(cx);
33/// switch(attrs: attributes! { id=(&airplane_mode) checked="" })
34/// label(attrs: attributes! { for=(&airplane_mode) }, "Airplane mode")
35/// </div>
36/// }
37/// ```
38#[component]
39pub async fn switch(cx: &Cx, #[default] mut attrs: Attributes) -> Result<impl View> {
40 // The thumb cannot be drawn by the `<input>` itself, which renders no
41 // children or pseudo-elements: it is a sibling overlaid on the track,
42 // slid to the far end by the input's `peer` state while checked.
43 Ok(view! {
44 <span
45 class=(class!(
46 "peer relative inline-flex shrink-0 has-[:disabled]:opacity-50",
47 attrs.remove("class"),
48 ))
49 >
50 <input type="checkbox" role="switch" class=(SWITCH) (attrs)>
51 <span class=(THUMB)></span>
52 </span>
53 })
54}