fix(fast-html): fix event bindings inside f-when not firing after hydration#7327
Open
mohamedmansour wants to merge 14 commits intomicrosoft:mainfrom
Open
fix(fast-html): fix event bindings inside f-when not firing after hydration#7327mohamedmansour wants to merge 14 commits intomicrosoft:mainfrom
mohamedmansour wants to merge 14 commits intomicrosoft:mainfrom
Conversation
During hydration, when a `<f-when>` condition references a server-only property (not defined on the client element class), the binding evaluates to falsy. This causes the inner template to be skipped entirely, so event listeners like `@click` are never attached to the SSR-rendered DOM. **fast-html** (`utilities.ts`): - `resolveWhen` now returns `true` during the hydrating stage when the condition evaluates to falsy, trusting the server-rendered state. **fast-element** (`html-binding-directive.ts`): - `updateContent` skips creating a new view during hydration when no view boundaries exist and the target is empty, preventing DOM mismatch for conditions the server evaluated as false.
akroshg
reviewed
Mar 19, 2026
janechu
reviewed
Mar 19, 2026
change/@microsoft-fast-element-ccc364c3-3d9a-4477-a877-812d7fc72bff.json
Outdated
Show resolved
Hide resolved
change/@microsoft-fast-html-1cbbfa63-0099-407f-9cd2-36fe3f44f3c3.json
Outdated
Show resolved
Hide resolved
Co-authored-by: Jane Chu <7559015+janechu@users.noreply.github.com>
Collaborator
|
/AzurePipelines run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Contributor
Author
|
/AzurePipelines run |
|
Commenter does not have sufficient privileges for PR 7327 in repo microsoft/fast |
Collaborator
|
/AzurePipelines run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
janechu
previously approved these changes
Mar 19, 2026
Collaborator
|
I'm OK with this for now, I think we need a more robust solution in future that feels more modular, our hydration solution is a little too "after the fact" right now. |
Needs discussion, this breaks several conventions.
radium-v
requested changes
Mar 19, 2026
Co-authored-by: John Kreitlow <863023+radium-v@users.noreply.github.com>
…ohamedmansour/fast into fix/hydration-under-conditions
The resolveWhen hydration override was returning true for ALL falsy binding results during hydration, including properties explicitly set to false on the client element. This caused a mismatch where server- rendered content persisted even though the client value was false. resolveWhen (utilities.ts): - Use pathResolver to check the raw property value before the expression resolver normalizes it to a boolean. - Only override to true during hydration when the raw value is undefined (property not defined on the client, i.e. server-only). - When the property IS defined but explicitly falsy (e.g. false, 0), return the actual result to respect the client state. updateContent (html-binding-directive.ts): - Revert the overly broad null/undefined hydration preservation. The resolveWhen fix now handles server-only properties by returning true (so a template reaches updateContent, not null), making the blanket null preservation unnecessary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2042f74 to
5eba2ed
Compare
0b9f0c3 to
96d7c75
Compare
radium-v
requested changes
Mar 19, 2026
radium-v
reviewed
Mar 19, 2026
packages/fast-html/test/fixtures/when-false-explicit/when-false-explicit.spec.ts
Outdated
Show resolved
Hide resolved
The approach of manually walking parentContext/parent chain to resolve event handler 'this' context inside f-repeat is not how the repeat directive works. This needs a proper solution that expands binding capabilities to allow context property access within repeat directives. Reverts template.ts attributeBinding changes and removes repeat-event test fixture. To be tracked as a separate issue. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Consolidate the when-false-explicit test scenario into the when-event fixture as both test f-when hydration behavior. Adds a test-element-false element with an explicit someprop=false to the existing fixture. 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
During hydration, when a
<f-when>condition references a server-only property (not defined on the client element class), the binding evaluates to falsy. This causes the inner template to be skipped entirely, so event listeners like@clickare never attached to the SSR-rendered DOM.How it was done
fast-html (
utilities.ts):resolveWhennow usespathResolverto check the raw property value before the expression resolver normalizes it. During hydration, it only overrides totruewhen the raw value isundefined(property not defined on the client, i.e. server-only). When the property IS defined but explicitly falsy (e.g.
false,0), it respects the client value to avoid a hydration mismatch.fast-element (
html-binding-directive.ts):updateContentskips creating a new view during hydration when no view boundaries exist and the target is empty, preventing DOM mismatch for conditions the server evaluated as false.Tests added
when-event— verifies@clickinside<f-when>fires after hydration (server-only property)when-false-explicit— verifies<f-when>respects an explicitfalsevalue and removes server-rendered contentFixes #7321