Repository navigation
feat(forms): render any native form control under rx.form.control - #7859
Conversation
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 only read each control's own name, so compiling such a form warned that the control is submitted by its id, and a TypedDict submit handler raised a form field mismatch for the field the control fills. Walk form controls with the name their enclosing form field control passes on: its own name, or else the enclosing form field's. A form control without a child renders an input and is the control itself; with a child it names the child. Components opt into these roles with the new _is_form_field and _is_form_field_control class flags, set on rx.form.field and rx.form.control. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESN8DjjKz1VPEvFQd5BuvU
rx.form.control did not declare name, so a name passed to it landed in its style as CSS while the browser still submitted the control under the enclosing field's name. The form walk read that undeclared attribute and took it as the control's name, so a TypedDict submit handler could fail for a form the browser submits correctly. Declare name on FormControl so Radix receives it and prefers it over the field's name, which is what the walk already assumes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESN8DjjKz1VPEvFQd5BuvU
Compare the deprecation warning, the rendered control props and the TypedDict mismatch error in full, as the testing guidelines now ask, instead of checking fragments of them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESN8DjjKz1VPEvFQd5BuvU
[Medium impact] The reviewed changes appear safe to merge. Summary
No new actionable issues were found in the changes since the previous review. Tests were inspected, not run. No previous review threads were supplied. Reviews (5) · Last reviewed commit: "fix(forms): render a form control's chil..." · Reviewed by Greptile |
…hild only Drop the _is_form_field and _is_form_field_control class variables from Component: rx.form.field and rx.form.control set the attributes and the form walk reads them with getattr, so nothing else carries them. Pass the name a form field control supplies to the child it renders only. A hidden input nested in that child, such as one in an rx.input.slot, is not named by Radix, so it keeps its warning that submitting it by id is deprecated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESN8DjjKz1VPEvFQd5BuvU
rx.form.control only accepted rx.input and rx.debounce_input as its child, so a textarea or a low-level input, textarea or select could not take a form field's name and validation messages. Radix Form.Control composes with any native form control, and with nothing else: its other primitives such as Checkbox and Select do not work under it. Accept every component backed by a native input, select or textarea, which covers rx.text_area, rx.el.input, rx.el.textarea and rx.el.select, and keep rejecting the rest with a message that says where those go. A child is only rendered as the control with asChild, so set it when a child is given. The Playwright test submits a form with one field per accepted control and checks that each carries its field's name and label id, that the required textarea blocks submission and shows its message, and that the payload holds every value. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ESN8DjjKz1VPEvFQd5BuvU
62c17e8 to
be04db7
Compare
Merging this PR will improve performance by 5.69%2 warnings
Performance Changes
Tip Curious why performance improved? Comment Comparing |
There was a problem hiding this comment.
1 issue found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/integration/tests_playwright/test_radix_form_control.py">
<violation number="1" location="tests/integration/tests_playwright/test_radix_form_control.py:17">
P2: This test does not cover `rx.debounce_input`, which `rx.form.control` accepts. Add a `debounce_input` field, for example `form_field("debounced", rx.debounce_input(rx.el.input(default_value="debounced input")))`, and add it to `FIELD_NAMES` and the expected submitted dict. Otherwise the docstring's claim about every accepted control is not backed by the test.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
# Conflicts: # docs/library/forms/form-ll.md # pyi_hashes.json # tests/units/components/forms/test_form.py
…hild=False An explicit as_child=False with a child made Radix render an <input> with children, which React refuses, so the page failed to render. The Playwright test now relies on the default instead of passing as_child=True.
There was a problem hiding this comment.
2 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/reflex-components-radix/src/reflex_components_radix/primitives/form.py">
<violation number="1" location="packages/reflex-components-radix/src/reflex_components_radix/primitives/form.py:20">
P2: `FormControl.create` rejects custom components that directly render a native `input`, `select`, or `textarea` because it checks only concrete class inheritance. Accept native-tag children in addition to the known wrappers so the advertised “component rendering” contract covers custom native controls.</violation>
<violation number="2" location="packages/reflex-components-radix/src/reflex_components_radix/primitives/form.py:20">
P2: `DebounceInput` is accepted without checking the control it wraps. `rx.debounce_input(rx.checkbox(on_change=...))` passes this check, even though `rx.checkbox` is a Radix control the rejection message says must be refused. Check the wrapped element's type, or reject `DebounceInput` children whose `element` is not a native control.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
All Submissions:
Type of change
Description
Stacked on #7724, which teaches form compilation that a control rendered by
rx.form.controltakes itsrx.form.field's name.rx.form.controlonly acceptedrx.inputandrx.debounce_inputas its child, so a textarea or a low-level input, textarea or select could not take a form field'snameand validation messages:Upstream Radix
Form.Controlcomposes with any native form control, and with nothing else: the Radix docs state that it cannot yet be composed with the other form primitives such as Checkbox and Select.FormControl.createnow accepts every component backed by a nativeinput,selectortextarea, which coversrx.input,rx.text_area,rx.debounce_input,rx.el.input,rx.el.textareaandrx.el.select, and keeps rejecting the rest with a message that says to give those controls anameand place them under the root or field instead.asChild, soas_childis set whenever a child is given, even over an explicitas_child=False; without it Radix renders an<input>with children, which React refuses and the page fails to render.Changes To Core Features:
Unit tests cover acceptance of each native control and the exact rejection message. The new Playwright test
tests/integration/tests_playwright/test_radix_form_control.pyruns a form with one field per accepted control, including a fully controlled input that compiles toDebounceInput, and checks that each control carries its field'snameand theidits label points to, that a required textarea blocks submission and shows itsrx.form.message, and that the submitted payload holds every value, with no page errors.Generated by Claude Code