feat: propagate unbound state to all descendant custom elements#7423
Open
feat: propagate unbound state to all descendant custom elements#7423
Conversation
Custom elements now always receive the current root state as a base for their child state, with per-element HTML attributes overlaid on top. Previously, only entry-level (root) custom elements received the full root state; nested elements built their state entirely from attributes. This change ensures unbound state keys propagate through the entire element tree automatically, so child elements can reference any ancestor state key without explicit attribute bindings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e-to-child-elements
There was a problem hiding this comment.
Pull request overview
Updates the microsoft-fast-build Rust renderer so nested custom elements inherit their parent/root state by default, allowing unbound state keys (e.g. {{text}}) to resolve throughout the custom element tree without requiring explicit attribute bindings.
Changes:
- Adjusts
render_custom_elementstate construction to always base child state on the current root/parent state, then overlay per-element attributes. - Updates and adds Rust tests to validate state propagation through nested custom elements and override precedence.
- Updates crate docs (README + DESIGN) to reflect the new state propagation model and clarify
is_entrybehavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| crates/microsoft-fast-build/src/directive.rs | Changes child state building for custom elements to always inherit current root/parent state before overlaying attrs. |
| crates/microsoft-fast-build/tests/custom_elements.rs | Renames/updates an existing nested-element test and adds new tests for propagation, multi-level nesting, overrides, and non-entry rendering. |
| crates/microsoft-fast-build/README.md | Documents state propagation to nested elements and clarifies entry/root element attribute handling behavior. |
| crates/microsoft-fast-build/DESIGN.md | Updates internal design docs to reflect that is_entry now only affects opening-tag attribute handling, not child state building. |
When a custom element has no attributes that modify child state (only @event, ?bool, or directive attributes), the root state is now passed through by reference without cloning the HashMap. This avoids O(n) work per element in deep custom-element trees with large state objects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
📖 Description
This change updates the
microsoft-fast-buildRust crate so that all custom elements — whether at the entry level or deeply nested — receive the current root state as a base for their child state. Per-element HTML attributes are overlaid on top, with attribute-derived values taking precedence over any matching state keys.Previously, only entry-level (root) custom elements received the full root state; nested elements built their state entirely from HTML attributes. This meant that if a child element template referenced a state key like
{{text}}, the parent element had to explicitly pass it via an attribute binding (e.g.<my-child text="{{text}}">). With this change, unbound state keys propagate through the entire element tree automatically.Example
Both elements now render "Hello world" without explicit attribute bindings.
👩💻 Reviewer Notes
crates/microsoft-fast-build/src/directive.rs— therender_custom_elementfunction now always uses the current root state as a base for child state (removing theis_entrybranching for state building).is_entryflag still controls opening-tag attribute handling (root elements resolve primitive bindings, strip non-primitives; nested elements render resolved values and injectdata-fe-cmarkers).test_nested_custom_element_still_uses_attr_statewas updated totest_nested_custom_element_inherits_parent_stateto reflect the new expected behavior.📑 Test Plan
test_nested_custom_element_inherits_parent_state) to verify state propagation works.test_unbound_state_propagates_to_child_elements— exact scenario from the spectest_state_propagates_through_multiple_levels— three levels of nestingtest_child_attr_overrides_propagated_state— attribute values take precedencetest_non_entry_render_also_propagates_state— non-entry mode also propagates✅ Checklist
General
$ npm run change