diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index 205aae267..61ded4fd3 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -18,6 +18,7 @@ from reflex.event import ( prevent_default, ) from reflex.utils.imports import ImportDict +from reflex.utils.types import is_optional from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -382,6 +383,33 @@ class Input(BaseHTML): # Fired when a key is released on_key_up: EventHandler[key_event] + @classmethod + def create(cls, *children, **props): + """Create an Input component. + + Args: + *children: The children of the component. + **props: The properties of the component. + + Returns: + The component. + """ + from reflex.vars.number import ternary_operation + + value = props.get("value") + + # React expects an empty string(instead of null) for controlled inputs. + if value is not None and is_optional( + (value_var := Var.create(value))._var_type + ): + props["value"] = ternary_operation( + (value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] + & (value_var != Var(_js_expr="undefined")), + value, + Var.create(""), + ) + return super().create(*children, **props) + class Label(BaseHTML): """Display the label element.""" diff --git a/reflex/components/el/elements/forms.pyi b/reflex/components/el/elements/forms.pyi index 5870d4b22..dfab40b21 100644 --- a/reflex/components/el/elements/forms.pyi +++ b/reflex/components/el/elements/forms.pyi @@ -512,7 +512,7 @@ class Input(BaseHTML): on_unmount: Optional[EventType[[], BASE_STATE]] = None, **props, ) -> "Input": - """Create the component. + """Create an Input component. Args: *children: The children of the component. @@ -576,7 +576,7 @@ class Input(BaseHTML): class_name: The class name for the component. autofocus: Whether the component should take the focus once the page is loaded custom_attrs: custom attribute - **props: The props of the component. + **props: The properties of the component. Returns: The component. diff --git a/reflex/components/radix/themes/components/text_field.py b/reflex/components/radix/themes/components/text_field.py index 3dabe0936..7e6dfe85c 100644 --- a/reflex/components/radix/themes/components/text_field.py +++ b/reflex/components/radix/themes/components/text_field.py @@ -9,7 +9,9 @@ from reflex.components.core.breakpoints import Responsive from reflex.components.core.debounce import DebounceInput from reflex.components.el import elements from reflex.event import EventHandler, input_event, key_event +from reflex.utils.types import is_optional from reflex.vars.base import Var +from reflex.vars.number import ternary_operation from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent @@ -96,6 +98,19 @@ class TextFieldRoot(elements.Div, RadixThemesComponent): Returns: The component. """ + value = props.get("value") + + # React expects an empty string(instead of null) for controlled inputs. + if value is not None and is_optional( + (value_var := Var.create(value))._var_type + ): + props["value"] = ternary_operation( + (value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] + & (value_var != Var(_js_expr="undefined")), + value, + Var.create(""), + ) + component = super().create(*children, **props) if props.get("value") is not None and props.get("on_change") is not None: # create a debounced input if the user requests full control to avoid typing jank