Skip to content

feat(fast-build): strip state-passing binding attrs from root custom elements#7403

Draft
janechu wants to merge 4 commits intomainfrom
users/janechu/strip-entry-state-binding-attrs-on-root-elements
Draft

feat(fast-build): strip state-passing binding attrs from root custom elements#7403
janechu wants to merge 4 commits intomainfrom
users/janechu/strip-entry-state-binding-attrs-on-root-elements

Conversation

@janechu
Copy link
Copy Markdown
Collaborator

@janechu janechu commented Apr 7, 2026

Pull Request

📖 Description

When rendering the top-level entry HTML via render_entry_with_templates / render_entry_template_with_locator, root custom elements receive the full root state directly. Before this change, any {{binding}} attribute on a root element was resolved and written into the rendered HTML — e.g. list="{{list}}" became list="[Array]" or someData="[Object]". These attributes existed solely to forward state through the old attribute-based child state mechanism; with entry-level rendering that mechanism is bypassed, making the attributes both redundant and noisy.

This PR strips any attribute whose value is a pure {{expr}} double-brace binding from root custom element opening tags in the rendered HTML output. Static attributes (id, class, disabled, etc.) are preserved.

Additionally, render_entry_with_templates is now exposed as a WASM binding and the @microsoft/fast-build CLI is updated to use it when templates are provided, so the fixture build tool uses entry-level semantics by default.

📑 Test Plan

  • 4 new integration tests added for entry-level attribute stripping (static attr kept, binding attr stripped, mixed, and nested element unchanged)
  • npm run build:fixtures -w @microsoft/fast-html regenerates correctly: attribute, binding, and event fixtures no longer include resolved {{binding}} attrs on root elements
  • All Rust test suites pass (cargo test — 182 tests across all suites)

✅ Checklist

General

  • I have included a change request file using $ npm run change
  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

janechu and others added 4 commits April 7, 2026 10:52
…elements

When rendering entry HTML via render_entry_with_templates / render_entry_template_with_locator, root custom elements receive the full root state directly. Any attribute whose value is a pure {{expr}} double-brace binding was only needed to forward state via the attribute-based child state mechanism — with entry-level rendering that mechanism is bypassed, so these attributes are now stripped from the rendered HTML output.

Examples stripped: list="{{list}}", item_parent="{{item_parent}}", someData="{{someData}}"
Static attributes (id, class, disabled, etc.) are preserved.

Changes:
- attribute.rs: add is_state_passing_binding() and strip_entry_attrs() (strips client-only attrs + {{binding}} attrs)
- directive.rs: build_element_open_tag gains is_entry param; uses strip_entry_attrs when true
- wasm.rs: expose render_entry_with_templates WASM binding
- fast.js CLI: use render_entry_with_templates when templates are provided
- tests/custom_elements.rs: 4 new tests for entry-level attr stripping behaviour
- Regenerate attribute, binding, event fixture index.html files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ents; strip non-primitives

For entry-level root custom elements, {{binding}} attribute values are now resolved
from root state:
- Primitive (string/number/bool): rendered with resolved value, e.g. text="{{msg}}" → text="Hello world"
- Non-primitive (array/object/null): stripped — cannot be an HTML attribute value

Static attributes (no binding syntax) are passed through unchanged.

This is implemented via build_entry_element_open_tag in directive.rs which replaces
the earlier strip_entry_attrs approach. HTML escaping is applied to string values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant