Skip to main content

tablo_ui/components/primitives/
checkbox.rs

1// SYNC: topcoat-ui-registry@0.12.0 sha256:69af446eecbee0234f39ef1dfcde2d72b7ba89f13ad3b96506f9ef5dc40d0184 — do not hand-edit. Sync via `cargo xtask sync-topcoat-ui` (ADR-0007).
2use topcoat::{
3    Result,
4    context::Cx,
5    icon::{icon, iconify::iconify_icon},
6    view::{Attributes, StaticClass, View, attributes, class, component, view},
7};
8
9/// Classes for the native checkbox input and its checked state.
10const CHECKBOX: StaticClass = class!(
11    "peer size-4 shrink-0 appearance-none rounded-[4px] border border-border",
12    "bg-background transition-colors outline-none",
13    "checked:border-primary checked:bg-primary",
14    "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
15    "focus-visible:ring-offset-background disabled:pointer-events-none",
16);
17
18/// A styled native checkbox.
19///
20/// Pass input attributes and event handlers through `attrs`. Classes apply to the
21/// wrapper, while other attributes go on the `<input>`. Use `checked` for the initial
22/// state. The indeterminate state requires setting a DOM property and has no custom
23/// styling.
24///
25/// ```ignore
26/// view! {
27///     <div class="flex items-center gap-2">
28///         let terms = element_id(cx);
29///         checkbox(attrs: attributes! { id=(&terms) name="terms" checked="" })
30///         label(attrs: attributes! { for=(&terms) }, "Accept terms")
31///     </div>
32/// }
33/// ```
34#[component]
35pub async fn checkbox(cx: &Cx, #[default] mut attrs: Attributes) -> Result<impl View> {
36    // The checkmark cannot be drawn by the `<input>` itself, which renders no
37    // children or pseudo-elements: it is a sibling icon overlaid on the
38    // control, revealed by the input's `peer` state while checked.
39    Ok(view! {
40        <span
41            class=(class!(
42                "peer relative inline-flex shrink-0 has-[:disabled]:opacity-50",
43                attrs.remove("class"),
44            ))
45        >
46            <input type="checkbox" class=(CHECKBOX) (attrs)>
47            icon(
48                data: iconify_icon!("lucide:check"),
49                attrs: attributes! {
50                    class="pointer-events-none absolute inset-0 m-auto size-3.5 \
51                        text-primary-foreground opacity-0 peer-checked:opacity-100"
52                }
53            )
54        </span>
55    })
56}