Skip to content

fix(fast-html): fix event bindings inside f-when not firing after hydration#7327

Open
mohamedmansour wants to merge 14 commits intomicrosoft:mainfrom
mohamedmansour:fix/hydration-under-conditions
Open

fix(fast-html): fix event bindings inside f-when not firing after hydration#7327
mohamedmansour wants to merge 14 commits intomicrosoft:mainfrom
mohamedmansour:fix/hydration-under-conditions

Conversation

@mohamedmansour
Copy link
Contributor

@mohamedmansour mohamedmansour commented Mar 19, 2026

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 @click are never attached to the SSR-rendered DOM.

How it was done

fast-html (utilities.ts):

  • resolveWhen now uses pathResolver to check the raw property value before the expression resolver normalizes it. During hydration, it only overrides to true 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), it respects the client value to avoid a hydration mismatch.

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.

Tests added

  • when-event — verifies @click inside <f-when> fires after hydration (server-only property)
  • when-false-explicit — verifies <f-when> respects an explicit false value and removes server-rendered content

Fixes #7321

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.
@mohamedmansour mohamedmansour changed the title fix: Fix event bindings inside f-when not firing after hydration fix(fast-html): fix event bindings inside f-when not firing after hydration Mar 19, 2026
Co-authored-by: Jane Chu <7559015+janechu@users.noreply.github.com>
@janechu
Copy link
Collaborator

janechu commented Mar 19, 2026

/AzurePipelines run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@mohamedmansour
Copy link
Contributor Author

/AzurePipelines run

@azure-pipelines
Copy link

Commenter does not have sufficient privileges for PR 7327 in repo microsoft/fast

@janechu
Copy link
Collaborator

janechu commented Mar 19, 2026

/AzurePipelines run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

janechu
janechu previously approved these changes Mar 19, 2026
@janechu
Copy link
Collaborator

janechu commented Mar 19, 2026

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.

@janechu janechu dismissed their stale review March 19, 2026 21:46

Needs discussion, this breaks several conventions.

@mohamedmansour mohamedmansour changed the title fix(fast-html): fix event bindings inside f-when not firing after hydration fix(fast-html): fix event bindings inside f-when/f-repeat not firing after hydration Mar 19, 2026
Andrew Ritz and others added 6 commits March 19, 2026 15:23
Co-authored-by: John Kreitlow <863023+radium-v@users.noreply.github.com>
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>
@mohamedmansour mohamedmansour force-pushed the fix/hydration-under-conditions branch from 2042f74 to 5eba2ed Compare March 19, 2026 23:29
@radium-v radium-v self-requested a review March 19, 2026 23:30
@mohamedmansour mohamedmansour force-pushed the fix/hydration-under-conditions branch from 0b9f0c3 to 96d7c75 Compare March 19, 2026 23:31
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>
@mohamedmansour mohamedmansour changed the title fix(fast-html): fix event bindings inside f-when/f-repeat not firing after hydration fix(fast-html): fix event bindings inside f-when not firing after hydration Mar 20, 2026
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.

<f-when> Does Not Re-evaluate After Hydration

4 participants