fix(forms): take a form control's name from its rx.form.field

Draft
MA
3d ago
+198-57

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • This change requires a documentation update

Description

Radix passes an rx.form.field's name to the control rendered by its rx.form.control, so an rx.input there submits under the field's name even without a name of its own. The static form walk in forms.py only read each control's own name, so compiling a form like the one in the low-level form docs:

rx.form.root(
    rx.form.field(
        rx.form.control(rx.input(id="email", type="email"), as_child=True),
        name="email",
    ),
    on_submit=State.handle_submit,
)

warned that the control with id 'email' is submitted by its id and will stop being submitted in 0.11, and a TypedDict submit handler raised a "Form field mismatch" error for the field the control fills.

The walk now carries the name an enclosing form field control passes on: its own name, or else that of the enclosing form field. A control's own name still wins, matching Radix's slot merge order. An rx.form.control with no child renders an input itself, so it now counts as a form control; with a child it names that child, including a debounced input. A control that sits in a named field but outside rx.form.control, or in an unnamed field, still warns, since Radix does not name it.

Components opt into these roles with the new _is_form_field and _is_form_field_control class flags on Component, next to the existing _is_form_control, set on rx.form.field and rx.form.control. Core reads them with getattr, so no sibling floors change.

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Regression tests in tests/units/components/forms/test_form.py cover the no-warning cases (slot child, bare control, debounced child, control-level name), the still-warning cases, and TypedDict validation with static, dynamic, and mismatched field names. Docs for both form pages note the inherited name, and news fragments are added for reflex-base, reflex-components-core, and reflex-components-radix.


Generated by Claude Code