Conversation
This was referenced Apr 6, 2026
There was a problem hiding this comment.
Pull request overview
This PR updates @microsoft/fast-build’s server-side renderer so custom element state-building better matches FAST runtime conventions (camelCase property access, : property bindings, and skipping @ event bindings), and also adds support for accessing .length on arrays in template expressions.
Changes:
- Build child element state with
:-prefix stripping, kebab-case → camelCase aliasing, and skipping@eventattributes. - Add
.lengthsupport when resolving nested properties on arrays. - Expand test coverage for the above, plus JSON array/object literals in custom element attributes.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/microsoft-fast-build/src/directive.rs | Adjusts custom element state construction (@ skip, : strip, kebab→camel alias) and extends attribute value parsing (JSON literals). |
| crates/microsoft-fast-build/src/context.rs | Adds array .length handling in nested property resolution. |
| crates/microsoft-fast-build/tests/f_when.rs | Adds f-when condition tests using items.length. |
| crates/microsoft-fast-build/tests/custom_elements.rs | Adds tests for kebab→camel aliasing, : property bindings, @ skipping, and JSON literal attribute parsing. |
| crates/microsoft-fast-build/tests/bindings.rs | Adds direct binding tests for items.length (including nested and empty cases). |
| crates/microsoft-fast-build/README.md | Documents new custom-element attribute/state behaviors (:/@ handling, kebab→camel alias). |
| crates/microsoft-fast-build/DESIGN.md | Updates design notes for state-building rules (skip @, strip :; camel alias). |
| change/@microsoft-fast-build-fix-kebab-bindings-1314e0de-ff4c-4dd5-8cc5-2e8fc04bc0aa.json | Patch change file for kebab→camel and : binding fixes. |
| change/@microsoft-fast-build-fix-array-length-3d13d21c-1594-4fe1-babf-8123aa5e098e.json | Patch change file for array .length support. |
…ssions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…perty bindings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The JSON array/object literal attribute parsing belongs on the fix-json-literal-attributes branch (PR #7395), not here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…custom element state Replace camelCase aliasing with simple lowercase normalisation: all attribute keys have their colon prefix stripped, hyphens removed, and are converted to lowercase before being stored in child element state. This mirrors the default browser behaviour for case-insensitive HTML attribute names, so selectedUserId, selected-user-id, and SelectedUserID all resolve to the same selecteduserid key. Templates must reference the lowercase form. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rmalisation Hyphens are kept in attribute keys; only the case is lowercased. selected-user-id stays as selected-user-id while selectedUserId becomes selecteduserid. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ibute value types - Add strip_event_attrs() in attribute.rs — removes @attr="{...}" from rendered element tags while preserving the data-fe-c binding count so the FAST runtime still allocates the correct number of binding slots. Applied to both the outer custom element tag and all tags inside the rendered shadow DOM template. - Simplify attribute_to_json_value: literal attribute values are always String (only a valueless boolean attribute produces Bool(true)). Booleans and numbers must arrive via {{binding}} expressions. - Attribute keys are kept exactly as written after stripping ':' — no case transformation. HTML attributes are always lowercase/kebab-case; property bindings preserve their original casing. - Update tests and docs accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ercase attr keys - Extend strip_client_only_attrs (renamed from strip_event_attrs) to also remove :attr property binding attributes from rendered HTML output, in addition to @attr event bindings. Both are FAST client-only constructs. - Add .to_lowercase() back to attribute key normalisation: HTML attribute names are case-insensitive and browsers store them lowercase, so isEnabled becomes isenabled. Hyphens are preserved (selected-user-id unchanged). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the raw byte-scanner with a declarative approach that reuses the existing parse_element_attributes / read_tag_name helpers: - extract tag name via read_tag_name - parse attributes via parse_element_attributes - filter out @ / : prefixed names - rebuild the tag, preserving >, />, or no-closing as appropriate Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Property bindings (:attr) represent JavaScript property names which are case-sensitive. Strip the leading : but preserve the original casing so :myProp -> key "myProp" in child state. Plain HTML attributes still get lowercased (browsers normalise attribute names to lowercase). - directive.rs: split key normalisation — :prop preserves casing, HTML attr lowercases - tests: add test_custom_element_camel_property_binding; update existing colon binding test comment - README.md: update attribute→state table and description; fix @click examples to show it stripped from rendered HTML - DESIGN.md: update step 4 to describe separate normalisation rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…keys
Switch parent templates in bool-attr hydration tests from plain HTML
attributes to property bindings (:isEnabled, :activeGroup, :currentGroup)
so the child scope receives keys with their original JS property name
{{activeGroup == currentGroup}} instead of their lowercased equivalents.
Also update the README boolean binding example to show camelCase property
names in the shadow template.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Property bindings (:prop) are client-side only — like @event bindings they are resolved by the FAST client runtime and have no meaning in SSR state. They are already stripped from rendered HTML; now they are also not added to the child element's rendering scope. - directive.rs: extend the client-only skip to include : prefix alongside @ - tests/custom_elements.rs: replace colon binding tests with test_custom_element_colon_property_binding_skipped; remove camel test - tests/hydration.rs: revert parent templates to plain HTML attrs (isEnabled, activeGroup, currentGroup) and child templates back to lowercase state keys (isenabled, activegroup, currentgroup) - README.md: update table and description; fix bool-attr example back to lowercase state keys - DESIGN.md: update steps 4 and 7 to describe unified client-only skip Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- test_custom_element_kebab_attr_camel_in_template → test_custom_element_kebab_attr_hyphens_preserved (no camel conversion; hyphens are kept) - test_custom_element_multi_word_kebab_to_camel → test_custom_element_multi_word_kebab_attrs (no camel conversion; kebab keys passed through as-is) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ad2d43d to
e524480
Compare
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.
Summary
Fixes how the
microsoft-fast-buildRust SSR crate handles custom element attributes when building child rendering state and producing declarative shadow DOM HTML. Rebased on top of #7398 (data-*→ dataset mapping).Attribute → child state key rules
isEnabled="..."isenabledselected-user-id="42"selected-user-idfoo="{{bar}}"foo(resolved from parent state)data-date-of-birth="..."{"dataset": {"dateOfBirth": ...}}:myProp="{{expr}}"@click="{fn()}"Attribute value rules
disabled) →truein child statecount="42"is"42", not the number42{{binding}}expressions so the resolvedJsonValueflows from parent stateClient-only bindings — stripped from HTML, skipped from state
Both
@eventand:propertybindings are removed from all rendered HTML (outer element open tag and all tags inside the declarative shadow DOM) and are not added to the child element's rendering scope. Thedata-fe-cbinding count is preserved so the FAST runtime still allocates the correct number of binding slots.Changes
directive.rs:@and:prefixed attrs both skipped when building child state; all HTML attribute keys lowercased;attribute_to_json_valuesimplified (strings only, no numeric/boolean coercion for literals); dataset logic from feat(microsoft-fast-build): map data-* attributes to nested dataset state #7398 preservedattribute.rs:strip_client_only_attrsremoves@attrand:attrfrom any opening tag; refactored to useparse_element_attributes+read_tag_namenode.rs:strip_client_only_attrswired into hydration tag scan so shadow template HTML is also cleanedtest_custom_element_colon_property_binding_skippedverifies property bindings are stripped from HTML and not passed to child scope; stale test names fixed