Description: Utilizing the body tag within a React component violates HTML specifications regarding nested body tags and leads to significant runtime complications. In our testing, projects built using Vite/React on WSL2 and executed in browser environments such as Google Chrome and Mozilla Firefox experienced a complete hang or freeze of the browser tab when focusing on an input or textarea element inside a nested body.
This issue is not merely environment-specific to the build setup; rather, it appears to be a broader architectural conflict related to React's infinite reconciliation loop, potentially manifesting across various platforms during runtime. This lack of explicit error messaging makes it exceptionally challenging for developers to identify the root cause and conduct effective debugging.
Proposed Rule: A new rule to prevent the use of body tags in JSX, similar to how eslint-plugin-react might handle other illegal nesting or semantic errors.
Examples of incorrect code:
const App = () => (
<body>
<input type="text" />
</body>
);
Examples of correct code:
const App = () => (
<div>
<input type="text" />
</div>
);
Why this should be added: To improve Developer Experience (DX) by catching a "silent killer" bug that leads to browser crashes rather than simple console errors.
Root Cause Analysis:
-
Parser Flattening & DOM Mismatch: According to the HTML Living Standard, a body element cannot be nested. When the browser's HTML parser encounters a second body tag, it performs "Error Recovery" by ignoring the nested tag and flattening the structure. This leads to a critical discrepancy where the Virtual DOM expects a nested hierarchy, but the Real DOM has been forcefully restructured by the browser.
-
Event Delegation & Focus Path Failure: React uses a single event listener at the root for event delegation. When an input or textarea inside this malformed structure receives focus, the browser's internal Focus Path calculation conflicts with React's event synthetic system. In a broken DOM tree, the bubbling of focus events can trigger recursive updates or fail to find a valid parent, leading to a terminal UI Thread Hang (Freeze).
-
The fundamental cause of the browser freeze is not merely the repetitive DOM patching, but rather the JavaScript execution context hijacking the Event Loop. When the DOM structure is malformed (due to nested tags), React's internal logic—specifically within its event delegation system or reconciliation process—enters a synchronous infinite loop. Since the Main Thread is occupied indefinitely by this continuous JavaScript execution, the Event Loop is unable to proceed to subsequent tasks such as UI rendering or handling other user inputs. This results in a total hang of the browser tab, as the thread never yields back to the browser's rendering engine.
Description: Utilizing the body tag within a React component violates HTML specifications regarding nested body tags and leads to significant runtime complications. In our testing, projects built using Vite/React on WSL2 and executed in browser environments such as Google Chrome and Mozilla Firefox experienced a complete hang or freeze of the browser tab when focusing on an input or textarea element inside a nested body.
This issue is not merely environment-specific to the build setup; rather, it appears to be a broader architectural conflict related to React's infinite reconciliation loop, potentially manifesting across various platforms during runtime. This lack of explicit error messaging makes it exceptionally challenging for developers to identify the root cause and conduct effective debugging.
Proposed Rule: A new rule to prevent the use of body tags in JSX, similar to how eslint-plugin-react might handle other illegal nesting or semantic errors.
Examples of incorrect code:
Examples of correct code:
Why this should be added: To improve Developer Experience (DX) by catching a "silent killer" bug that leads to browser crashes rather than simple console errors.
Root Cause Analysis:
Parser Flattening & DOM Mismatch: According to the HTML Living Standard, a body element cannot be nested. When the browser's HTML parser encounters a second body tag, it performs "Error Recovery" by ignoring the nested tag and flattening the structure. This leads to a critical discrepancy where the Virtual DOM expects a nested hierarchy, but the Real DOM has been forcefully restructured by the browser.
Event Delegation & Focus Path Failure: React uses a single event listener at the root for event delegation. When an input or textarea inside this malformed structure receives focus, the browser's internal Focus Path calculation conflicts with React's event synthetic system. In a broken DOM tree, the bubbling of focus events can trigger recursive updates or fail to find a valid parent, leading to a terminal UI Thread Hang (Freeze).
The fundamental cause of the browser freeze is not merely the repetitive DOM patching, but rather the JavaScript execution context hijacking the Event Loop. When the DOM structure is malformed (due to nested tags), React's internal logic—specifically within its event delegation system or reconciliation process—enters a synchronous infinite loop. Since the Main Thread is occupied indefinitely by this continuous JavaScript execution, the Event Loop is unable to proceed to subsequent tasks such as UI rendering or handling other user inputs. This results in a total hang of the browser tab, as the thread never yields back to the browser's rendering engine.