Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Add text node support to FragmentInstance operations by jackpope · Pull Request #35630 · react/react · GitHub
Skip to content

Add text node support to FragmentInstance operations - #35630

Merged
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes
Jan 28, 2026
Merged

Add text node support to FragmentInstance operations#35630
jackpope merged 1 commit into
react:mainfrom
jackpope:fr-text-nodes

Conversation

@jackpope

@jackpopejackpope commented Jan 26, 2026

Copy link
Copy Markdown
Collaborator

This PR adds text node support to FragmentInstance operations, allowing fragment refs to properly handle fragments that contain text nodes (either mixed with elements or text-only).

Not currently adding/removing new text nodes as we don't need to track them for events or observers in DOM. Will follow up on this and with Fabric support.

Support through parent element

  • dispatchEvent
  • compareDocumentPosition
  • getRootNode

Support through Range API

  • getClientRects: Uses Range to calculate bounding rects for text nodes
  • scrollIntoView: Uses Range to scroll to text node positions directly

No support

  • focus/focusLast/blur: Noop for text-only fragments
  • observeUsing: Warns for text-only fragments in DEV
  • addEventListener/removeEventListener: Ignores text nodes, but still works on Fragment level through dispatchEvent

@react-sizebot

react-sizebot commented Jan 26, 2026

Copy link
Copy Markdown

Comparing: 87ae75b...1562e56

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-stable/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-stable/react-dom/cjs/react-dom-client.production.js+0.15%608.67 kB609.58 kB+0.16%107.63 kB107.80 kB
oss-experimental/react-dom/cjs/react-dom.production.js=6.84 kB6.84 kB=1.88 kB1.88 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js+0.14%674.60 kB675.51 kB+0.15%118.58 kB118.75 kB
facebook-www/ReactDOM-prod.classic.js+0.18%693.92 kB695.14 kB+0.18%121.98 kB122.19 kB
facebook-www/ReactDOM-prod.modern.js+0.18%684.31 kB685.52 kB+0.18%120.37 kB120.59 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name+/-BaseCurrent+/- gzipBase gzipCurrent gzip
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.production.js+0.29%11.29 kB11.32 kB+0.38%2.63 kB2.64 kB
oss-experimental/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
oss-stable/react-reconciler/cjs/react-reconciler-reflection.development.js+0.29%12.75 kB12.79 kB+0.26%2.71 kB2.72 kB
facebook-react-native/react-dom/cjs/ReactDOMClient-prod.js+0.20%595.71 kB596.93 kB+0.22%104.80 kB105.03 kB
facebook-react-native/react-dom/cjs/ReactDOMProfiling-prod.js+0.20%601.37 kB602.59 kB+0.21%105.94 kB106.16 kB

Generated by 🚫 dangerJS against 1562e56

return false;
});
if (hasText && !hasElement) {
console.warn(

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.

Shouldn't this be console.error?

while (i !== (resolvedAlignToTop ? -1 : children.length)) {
const child = children[i];
// For text nodes, use Range API to scroll to their position
if (enableFragmentRefsTextNodes && child.tag === HostText) {

@rickhanloniirickhanloniiJan 27, 2026

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.

We usually gate with just the flag

if(enableFragmentRefsTextNodes){if(child.tag===HostText){// ...}}

@jackpope
jackpopeforce-pushed the fr-text-nodes branch 3 times, most recently from d8d2710 to d4fbaabCompareJanuary 28, 2026 17:11
@jackpope
jackpope merged commit 875b064 into react:mainJan 28, 2026
234 checks passed
@jackpope
jackpope deleted the fr-text-nodes branch January 28, 2026 19:45
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
github-actionsBot pushed a commit that referenced this pull request Jan 28, 2026
This PR adds text node support to FragmentInstance operations, allowing
fragment refs to properly handle fragments that contain text nodes
(either mixed with elements or text-only).
Not currently adding/removing new text nodes as we don't need to track
them for events or observers in DOM. Will follow up on this and with
Fabric support.
## Support through parent element
- `dispatchEvent`
- `compareDocumentPosition`
- `getRootNode`
## Support through Range API
- `getClientRects`: Uses Range to calculate bounding rects for text
nodes
- `scrollIntoView`: Uses Range to scroll to text node positions directly
## No support
- `focus`/`focusLast`/`blur`: Noop for text-only fragments
- `observeUsing`: Warns for text-only fragments in DEV
- `addEventListener`/`removeEventListener`: Ignores text nodes, but
still works on Fragment level through `dispatchEvent`
DiffTrain build for [875b064](875b064)
jackpope added a commit that referenced this pull request Jan 28, 2026
Stacked on #35630
- Adds test case for compareDocumentPosition, missing before and also
extending to text nodes
- Adds event handling fixture case for text
- Adds getRootNode fixture case for text
jackpope added a commit that referenced this pull request Feb 11, 2026
Follow up to #35630
We don't currently have any operations that depend on the updating of
text nodes added or removed after Fragment mount. But for the sake of
completeness and extending the ability to any other host configs, this
change calls `commitNewChildToFragmentInstance` and
`deleteChildFromFragmentInstance` on HostText fibers.
Both DOM and Fabric configs early return because we cannot attach event
listeners or observers to text. In the future, there could be some
stateful Fragment feature that uses text that could extend this.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jackpope@react-sizebot@rickhanlonii