Skip to content

Commit 2f26609

Browse files
authored
ENG-6149: Checkbox component (#14)
1 parent 0c9b04b commit 2f26609

File tree

4 files changed

+147
-1
lines changed

4 files changed

+147
-1
lines changed

demo/demo/demo.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ def index() -> rx.Component:
1919
),
2020
content="Seriously, click me",
2121
),
22+
ui.checkbox(
23+
label="Click me",
24+
on_checked_change=lambda value: rx.toast.success(f"Value: {value}"),
25+
),
2226
ui.slider(
2327
on_value_committed=lambda value: rx.toast.success(f"Value: {value}"),
2428
class_name="max-w-xs",

reflex_ui/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"components.base.avatar": ["avatar"],
77
"components.base.badge": ["badge"],
88
"components.base.button": ["button"],
9+
"components.base.checkbox": ["checkbox"],
910
"components.base.scroll_area": ["scroll_area"],
1011
"components.base.select": ["select"],
1112
"components.base.skeleton": ["skeleton"],
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""Checkbox component from base-ui components."""
2+
3+
from __future__ import annotations
4+
5+
from reflex.components.component import Component, ComponentNamespace
6+
from reflex.components.el import Label
7+
from reflex.event import EventHandler, passthrough_event_spec
8+
from reflex.utils.imports import ImportVar
9+
from reflex.vars import Var
10+
11+
from reflex_ui.components.base_ui import PACKAGE_NAME, BaseUIComponent
12+
from reflex_ui.components.icons.hugeicon import hi
13+
from reflex_ui.utils.twmerge import cn
14+
15+
16+
class ClassNames:
17+
"""Class names for the checkbox component."""
18+
19+
ROOT = "flex size-4 items-center justify-center rounded-[4px] data-[checked]:bg-primary-9 data-[unchecked]:border data-[unchecked]:border-secondary-8 data-[disabled]:cursor-not-allowed data-[disabled]:border data-[disabled]:border-secondary-4 data-[disabled]:bg-secondary-3 hover:bg-secondary-3 transition-colors cursor-default"
20+
INDICATOR = (
21+
"flex text-white data-[unchecked]:hidden data-[disabled]:text-secondary-8"
22+
)
23+
LABEL = "text-sm text-secondary-12 font-medium flex items-center gap-2"
24+
CONTAINER = "flex flex-row items-center gap-2"
25+
26+
27+
class CheckboxBaseComponent(BaseUIComponent):
28+
"""Base component for checkbox components."""
29+
30+
library = f"{PACKAGE_NAME}/checkbox"
31+
32+
@property
33+
def import_var(self):
34+
"""Return the import variable for the checkbox component."""
35+
return ImportVar(tag="Checkbox", package_path="", install=False)
36+
37+
38+
class CheckboxRoot(CheckboxBaseComponent):
39+
"""The root checkbox component."""
40+
41+
tag = "Checkbox.Root"
42+
43+
# Whether the checkbox is initially ticked. To render a controlled checkbox, use the checked prop instead. Defaults to False.
44+
default_checked: Var[bool]
45+
46+
# Whether the checkbox is currently ticked. To render an uncontrolled checkbox, use the default_checked prop instead.
47+
checked: Var[bool]
48+
49+
# Event handler called when the checkbox is ticked or unticked.
50+
on_checked_change: EventHandler[passthrough_event_spec(bool, dict)]
51+
52+
# Whether the checkbox is in a mixed state: neither ticked, nor unticked. Defaults to False.
53+
indeterminate: Var[bool]
54+
55+
# Whether the component should ignore user interaction. Defaults to False.
56+
disabled: Var[bool]
57+
58+
# Whether the checkbox is required. Defaults to False.
59+
required: Var[bool]
60+
61+
# Identifies the field when a form is submitted.
62+
name: Var[str]
63+
64+
# The value of the selected checkbox.
65+
value: Var[str]
66+
67+
# Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button (e.g. <div>). Defaults to True.
68+
native_button: Var[bool]
69+
70+
# Whether the checkbox controls a group of child checkboxes. Must be used in a Checkbox Group. Defaults to False.
71+
parent: Var[bool]
72+
73+
# Whether the user should be unable to tick or untick the checkbox. Defaults to False.
74+
read_only: Var[bool]
75+
76+
@classmethod
77+
def create(cls, *children, **props) -> Component:
78+
"""Create the checkbox root component."""
79+
props["data-slot"] = "checkbox"
80+
cls.set_class_name(ClassNames.ROOT, props)
81+
return super().create(*children, **props)
82+
83+
84+
class CheckboxIndicator(CheckboxBaseComponent):
85+
"""The indicator that shows whether the checkbox is checked."""
86+
87+
tag = "Checkbox.Indicator"
88+
89+
@classmethod
90+
def create(cls, *children, **props) -> Component:
91+
"""Create the checkbox indicator component."""
92+
if len(children) == 0:
93+
children = (hi("Tick02Icon", size=14),)
94+
props["data-slot"] = "checkbox-indicator"
95+
cls.set_class_name(ClassNames.INDICATOR, props)
96+
return super().create(*children, **props)
97+
98+
99+
class HighLevelCheckbox(CheckboxRoot):
100+
"""High level wrapper for the Checkbox component."""
101+
102+
@classmethod
103+
def create(cls, *children, **props) -> Component:
104+
"""Create a high level checkbox component.
105+
106+
Args:
107+
*children: The content of the checkbox.
108+
**props: Additional properties to apply to the checkbox component.
109+
110+
Returns:
111+
The checkbox component and its indicator.
112+
"""
113+
class_name = props.pop("class_name", "")
114+
if label := props.pop("label", None):
115+
return Label.create(
116+
CheckboxRoot.create(
117+
CheckboxIndicator.create(),
118+
*children,
119+
**props,
120+
),
121+
label,
122+
class_name=cn(ClassNames.LABEL, class_name),
123+
)
124+
return CheckboxRoot.create(
125+
CheckboxIndicator.create(),
126+
*children,
127+
**props,
128+
class_name=class_name,
129+
)
130+
131+
132+
class CheckboxNamespace(ComponentNamespace):
133+
"""Namespace for Checkbox components."""
134+
135+
root = staticmethod(CheckboxRoot.create)
136+
indicator = staticmethod(CheckboxIndicator.create)
137+
high_level = staticmethod(HighLevelCheckbox.create)
138+
__call__ = staticmethod(HighLevelCheckbox.create)
139+
140+
141+
checkbox = CheckboxNamespace()

reflex_ui/components/base/switch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
class ClassNames:
1212
"""Class names for switch components."""
1313

14-
ROOT = "relative flex h-5 w-8 rounded-full bg-secondary-4 p-0.5 transition-colors duration-200 ease-out before:absolute before:rounded-full before:outline-offset-2 before:outline-primary-8 focus-visible:before:inset-0 data-[checked]:bg-primary-9 disabled:opacity-50 disabled:cursor-not-allowed"
14+
ROOT = "relative flex h-5 w-8 rounded-full bg-secondary-4 p-0.5 transition-colors duration-200 ease-out before:absolute before:rounded-full before:outline-offset-2 before:outline-primary-8 focus-visible:before:inset-0 data-[checked]:bg-primary-9 disabled:opacity-50 disabled:cursor-not-allowed cursor-default"
1515
THUMB = "aspect-square h-full rounded-full bg-white transition-transform duration-200 ease-out data-[checked]:translate-x-3 shadow-small"
1616

1717

0 commit comments

Comments
 (0)