Skip to content

ENG-9676 fix: route memo RestProp CSS props into css instead of dropping them#6605

Open
FarhanAliRaza wants to merge 2 commits into
reflex-dev:mainfrom
FarhanAliRaza:style-fix
Open

ENG-9676 fix: route memo RestProp CSS props into css instead of dropping them#6605
FarhanAliRaza wants to merge 2 commits into
reflex-dev:mainfrom
FarhanAliRaza:style-fix

Conversation

@FarhanAliRaza

@FarhanAliRaza FarhanAliRaza commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

A rx.RestProp only forwarded kwargs that matched a declared field of the target component; any other forwarded prop (e.g. font_weight) was emitted as a raw plain prop the target silently ignored. Track each RestProp target's field names during body evaluation so the call site can fold non-field props into emotion css, matching how a normal component handles unknown kwargs.

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

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)

New Feature Submission:

  • Does your submission pass the tests?
  • Have you linted your code locally prior to submission?

Changes To Core Features:

A `rx.RestProp` only forwarded kwargs that matched a declared field of the
target component; any other forwarded prop (e.g. `font_weight`) was emitted
as a raw plain prop the target silently ignored. Track each RestProp target's
field names during body evaluation so the call site can fold non-field props
into emotion `css`, matching how a normal component handles unknown kwargs.
@FarhanAliRaza FarhanAliRaza requested a review from a team as a code owner June 4, 2026 14:37
@FarhanAliRaza FarhanAliRaza changed the title fix: route memo RestProp CSS props into css instead of dropping them ENG-9676 fix: route memo RestProp CSS props into css instead of dropping them Jun 4, 2026
@codspeed-hq

codspeed-hq Bot commented Jun 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing FarhanAliRaza:style-fix (b89f189) with main (3653b8e)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes a silent data-loss bug where rx.RestProp only forwarded kwargs that matched a declared field of the target component; any other kwarg (e.g. font_weight) was emitted as a raw camelCased plain prop that the target silently ignored. The fix tracks each RestProp target's field names during body evaluation and routes non-field kwargs through convert_dict_to_style_and_format_emotion into an emotion css prop, matching how a direct component call handles unknown kwargs.

  • _rest_target_fields (a set[str]) is created before body evaluation and passed by reference through the lazy/eager lambda so _lift_rest_props can populate it as a side effect; rest_target_field_names() forces that evaluation before take_rest reads the set.
  • take_rest is extended with a second parameter: fields in rest_target_fields become camelCased plain props as before; everything else is collected and wrapped in a single css key via emotion formatting.
  • Unit and integration tests are updated/added to cover the CSS-forwarding path and the guard that real target fields remain plain props.

Confidence Score: 4/5

Safe to merge; the fix addresses a real silent-drop bug with a well-scoped, well-tested implementation and no regressions on common paths.

The core routing logic is correct: the shared-set mutation pattern for the lazy body, the field-vs-CSS classification, and the emotion formatting path all behave as intended. Two edge cases lack test coverage — convert_dict_to_style_and_format_emotion returning None when all style values normalise away, and memos with multiple RestProp targets whose field unions could misclassify a prop. Neither is likely to surface in typical usage, but both are worth hardening.

The take_rest method in memo.py around the convert_dict_to_style_and_format_emotion call (line ~1003) and the _lift_rest_props accumulator logic (line ~1095) deserve a second look for the None-return and multi-target edge cases.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/components/memo.py Core fix: tracks rest-target component field names during body evaluation, then routes non-field kwargs to emotion css instead of silently forwarding them as plain props. Logic is sound and all paths (eager and lazy body) are handled.
tests/units/components/test_memo.py Adds two new unit tests and updates an existing assertion to match the new routing behavior. Covers both the CSS-forwarding path and the "real target field stays as plain prop" guard case.
tests/integration/test_memo.py Integration test now passes font_weight="bold" through rx.RestProp and asserts the computed CSS value is "700"; small, focused addition that covers the real-browser path.

Comments Outside Diff (1)

  1. packages/reflex-base/src/reflex_base/components/memo.py, line 1095-1100 (link)

    P2 Multiple RestProp targets: field union may misclassify props

    When a memo body spreads rest onto two different components (e.g. rx.box(rest) and rx.text(rest)), rest_target_fields becomes the union of both components' fields. A kwarg that is a field of Box but not Text would then be forwarded as a plain prop even when the usage context targets Text, silently passing an unrecognised prop instead of routing it to css. The docs call this out in the accumulator comment, but the behaviour can surprise authors of multi-target memos. If this is intentional, a short note in the rest_target_field_names docstring would clarify the trade-off.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "fix: route memo RestProp CSS props into ..." | Re-trigger Greptile

Comment on lines +1003 to 1006
if css:
rest["css"] = LiteralVar.create(
convert_dict_to_style_and_format_emotion(css)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 convert_dict_to_style_and_format_emotion can return None

format_as_emotion returns None when its internal emotion_style dict ends up empty after processing (e.g. all entries are filtered or a Var-only style resolves to nothing). Passing None to LiteralVar.create would produce a css={null} prop in the JSX output, which silently drops all emotion styles at runtime. The if css: guard only checks the pre-conversion dict, not the output. A None check on the result would make this safe.

Adds the 6605 bugfix changelog entry documenting that `@rx.memo` forwards
undeclared RestProp kwargs into `css`, and regenerates the memo.pyi hash.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@rx.memo with rx.RestProp doesn't handle CSS props correctly

1 participant