Skip to content

refactor(core): add actionable hydration mismatch hints - #68529

Closed
SkyZeroZx wants to merge 1 commit into
angular:mainfrom
SkyZeroZx:hydration/browser-pattern
Closed

refactor(core): add actionable hydration mismatch hints#68529
SkyZeroZx wants to merge 1 commit into
angular:mainfrom
SkyZeroZx:hydration/browser-pattern

Conversation

@SkyZeroZx

Copy link
Copy Markdown
Contributor

Adds targeted hints for known browser HTML normalization cases that alter the DOM before Angular hydration.

Closes #56392

What is the current behavior?

Currently, the message may be somewhat generic and not indicate the real or complete cause of the problem.

What is the new behavior?

Missing explicit <tbody>

Spec :

“A tbody element's start tag may be omitted if the first thing inside the
tbody element is a tr element”

When a <tr> is written directly under <table>, the parser can
create the missing table body section before Angular hydrates.

See: https://html.spec.whatwg.org/multipage/syntax.html#optional-tags

<!-- User template -->
<table>
  <tr></tr>
</table>

<!-- DOM shape used for hydration -->
<table>
  <tbody>
    <tr></tr>
  </tbody>
</table>

Missing explicit <colgroup>

Spec :

“A colgroup element's start tag may be omitted if the first thing inside the
colgroup element is a col element”

When a <col> is written directly under <table>, the parser can
create the missing column group before Angular hydrates.

See: https://html.spec.whatwg.org/multipage/syntax.html#optional-tags

<!-- User template -->
<table>
  <col>
</table>

<!-- DOM shape used for hydration -->
<table>
  <colgroup>
    <col>
  </colgroup>
</table>

Nested anchors

Spec:

“Transparent, but there must be no interactive content descendant, a element
descendant, or descendant with the tabindex attribute specified.”

Parser:

“the first a element would be closed upon seeing the second one”

Nested links are invalid and the parser can close/restructure the
outer anchor before Angular hydrates.

See: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element
See: https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody

<!-- User template -->
<a>
  Outside
  <a>Click me</a>
</a>

<!-- DOM shape used for hydration -->
<a>
  Outside
</a>
<a>Click me</a>

Block content inside <p>

Spec :

“A p element's end tag can be omitted if the p element is immediately
followed by” elements like div, table, headings, lists, or another p.

The parser closes the paragraph before inserting the block, so
the block becomes a sibling instead of a child.

See: https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element

<!-- User template -->
<p>
  <div>Hello world!</div>
</p>

<!-- DOM shape used for hydration -->
<p></p>
<div>Hello world!</div>
<p></p>

Nested buttons

Spec :

“Phrasing content, but there must be no interactive content descendant and no
descendant with the tabindex attribute specified.”

Parser:

“If the stack of open elements has a button element in scope” then the parser
generates implied end tags and pops elements “until a button element has been
popped”.

When the parser sees the inner <button>, it closes the current
button first, so the buttons become siblings instead of nested nodes.

See: https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element
See: https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody

<!-- User template -->
<button>
  outside button
  <button>inner button</button>
</button>

<!-- DOM shape used for hydration -->
<button>
  outside button
</button>
<button>inner button</button>

Adds targeted hints for known browser HTML normalization cases that alter the DOM before Angular hydration.

Closes angular#56392
@angular-robot angular-robot Bot added the area: core Issues related to the framework runtime label May 3, 2026
@ngbot ngbot Bot added this to the Backlog milestone May 3, 2026
@SkyZeroZx
SkyZeroZx marked this pull request as ready for review May 3, 2026 17:45
@pullapprove
pullapprove Bot requested a review from thePunderWoman May 3, 2026 17:45

@thePunderWoman thePunderWoman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we were building out hydration, we explicitly didn't want to add in DOM validation like this, and I think this is strictly still true. The point of the original bug was not to identify these cases, but have better messages that point to the exact locations where the failure occurs. So IMHO this is too far down the DOM validation path.

@SkyZeroZx

Copy link
Copy Markdown
Contributor Author

Honestly, I could not think of a better solution at this moment without directly tying it to the browser’s behavior. The current diagnostic message is descriptive enough to indicate where the hydration mismatch happens, but in my opinion it does not clearly explain the why behind it.

My understanding is that, without considering how the browser parses and normalizes the HTML, there is no reliable way to explain the exact cause in these cases. Of course, I also understand that the DOM could have been changed by something external, such as browser extensions or third-party scripts, so the message cannot be completely certain.

I'm going to close this for now, as it's possibly not something we want and we might revisit it in the future.

@SkyZeroZx SkyZeroZx closed this May 9, 2026
@SkyZeroZx
SkyZeroZx deleted the hydration/browser-pattern branch May 18, 2026 17:47
@angular-automatic-lock-bot

Copy link
Copy Markdown

This pull request has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Jun 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area: core Issues related to the framework runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hydration: detect common mismatch patterns and produce a better error message

2 participants