Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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" + '
[flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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('^' + ".*" + ' [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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('^' + ".*" + ' [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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" + ' [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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('^' + ".*" + ' [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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('^' + ".*" + ' [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)
, '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); } })(); })(); [flags] land `enableTrustedTypesIntegration` (#35816) · react/react@074d96b · GitHub
Skip to content

Commit 074d96b

Browse files
authored
[flags] land enableTrustedTypesIntegration (#35816)
## Summary This flag enables React's integration with the browser [Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API). The Trusted Types API is a browser security feature that helps prevent DOM-based XSS attacks. When a site enables Trusted Types enforcement via `Content-Security-Policy: require-trusted-types-for 'script'`, the browser requires that values passed to DOM injection sinks (like `innerHTML`) are typed objects (`TrustedHTML`, `TrustedScript`, `TrustedScriptURL`) created through developer-defined sanitization policies, rather than raw strings. ### What changed Previously, React always coerced values to strings (via `'' + value`) before passing them to DOM APIs like `setAttribute` and `innerHTML`. This broke Trusted Types because it converted typed objects into plain strings, which the browser would then reject under Trusted Types enforcement. React now passes values directly to DOM APIs without string coercion, preserving Trusted Types objects so the browser can validate them. This applies to `dangerouslySetInnerHTML`, all HTML and SVG attributes, and URL attributes (`href`, `action`, etc). ### Before (broken) Using Trusted Types with something like`dangerouslySetInnerHTML` would throw: ```js const sanitizer = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { const clean = sanitizer.createHTML(text); // clean is a TrustedHTML object, but React would call '' + clean, // converting it back to a plain string before setting innerHTML. // Under Trusted Types enforcement, the browser rejects the string: // // TypeError: Failed to set 'innerHTML' on 'Element': // This document requires 'TrustedHTML' assignment. return <div dangerouslySetInnerHTML={{__html: clean}} />; } ``` ### After (works) React now passes the TrustedHTML object directly to the DOM without stringifying it: ```js const policy = trustedTypes.createPolicy('sanitizer', { createHTML: (input) => DOMPurify.sanitize(input), }); function Comment({text}) { // TrustedHTML objects are passed directly to innerHTML return <div dangerouslySetInnerHTML={{__html: policy.createHTML(text)}} />; } function UserProfile({bio}) { // String attribute values also preserve Trusted Types objects return <div data-bio={policy.createHTML(bio)} />; } ``` ## Non-breaking change - Sites using Trusted Types: React no longer breaks Trusted Types enforcement. TrustedHTML and TrustedScriptURL objects passed through React props are forwarded to the DOM without being stringified. - Sites not using Trusted Types: No behavior change. DOM APIs accept both strings and Trusted Types objects, so removing the explicit string coercion is functionally identical.
1 parent e33071c commit 074d96b

8 files changed

Lines changed: 7 additions & 9 deletions

‎packages/shared/ReactFeatureFlags.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export const disableLegacyMode: boolean = true;
208208
// in open source, but www codebase still relies on it. Need to remove.
209209
exportconstdisableCommentsAsDOMContainers: boolean=true;
210210

211-
exportconstenableTrustedTypesIntegration: boolean=false;
211+
exportconstenableTrustedTypesIntegration: boolean=true;
212212

213213
// Prevent the value and checked attributes from syncing with their related
214214
// DOM properties

‎packages/shared/forks/ReactFeatureFlags.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
6262
exportconstenableSuspenseCallback: boolean=true;
6363
exportconstenableTaint: boolean=true;
6464
exportconstenableTransitionTracing: boolean=false;
65-
exportconstenableTrustedTypesIntegration: boolean=false;
65+
exportconstenableTrustedTypesIntegration: boolean=true;
6666
exportconstenableUpdaterTracking: boolean=__PROFILE__;
6767
exportconstretryLaneExpirationMs=5000;
6868
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.native-oss.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const enableSuspenseAvoidThisFallback: boolean = false;
5050
exportconstenableSuspenseCallback: boolean=false;
5151
exportconstenableTaint: boolean=true;
5252
exportconstenableTransitionTracing: boolean=false;
53-
exportconstenableTrustedTypesIntegration: boolean=false;
53+
exportconstenableTrustedTypesIntegration: boolean=true;
5454
exportconstpassChildrenWhenCloningPersistedNodes: boolean=false;
5555
exportconstretryLaneExpirationMs=5000;
5656
exportconstsyncLaneExpirationMs=250;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const disableInputAttributeSyncing: boolean = false;
2626
exportconstenableScopeAPI: boolean=false;
2727
exportconstenableCreateEventHandleAPI: boolean=false;
2828
exportconstenableSuspenseCallback: boolean=false;
29-
exportconstenableTrustedTypesIntegration: boolean=false;
29+
exportconstenableTrustedTypesIntegration: boolean=true;
3030
exportconstdisableTextareaChildren: boolean=false;
3131
exportconstenableSuspenseAvoidThisFallback: boolean=false;
3232
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const enableSuspenseAvoidThisFallback = false;
4747
exportconstenableSuspenseCallback=false;
4848
exportconstenableTaint=true;
4949
exportconstenableTransitionTracing=false;
50-
exportconstenableTrustedTypesIntegration=false;
50+
exportconstenableTrustedTypesIntegration=true;
5151
exportconstenableUpdaterTracking=false;
5252
exportconstpassChildrenWhenCloningPersistedNodes=false;
5353
exportconstretryLaneExpirationMs=5000;

‎packages/shared/forks/ReactFeatureFlags.test-renderer.www.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const enableCreateEventHandleAPI: boolean = false;
2828
exportconstenableSuspenseCallback: boolean=true;
2929
exportconstdisableLegacyContext: boolean=false;
3030
exportconstdisableLegacyContextForFunctionComponents: boolean=false;
31-
exportconstenableTrustedTypesIntegration: boolean=false;
31+
exportconstenableTrustedTypesIntegration: boolean=true;
3232
exportconstdisableTextareaChildren: boolean=false;
3333
exportconstenableSuspenseAvoidThisFallback: boolean=true;
3434
exportconstenableCPUSuspense: boolean=false;

‎packages/shared/forks/ReactFeatureFlags.www-dynamic.js‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export const enableFragmentRefs: boolean = __VARIANT__;
3636
exportconstenableFragmentRefsScrollIntoView: boolean=__VARIANT__;
3737
exportconstenableFragmentRefsTextNodes: boolean=__VARIANT__;
3838
exportconstenableInternalInstanceMap: boolean=__VARIANT__;
39-
exportconstenableTrustedTypesIntegration: boolean=__VARIANT__;
4039
exportconstenableParallelTransitions: boolean=__VARIANT__;
4140

4241
exportconstenableEffectEventMutationPhase: boolean=__VARIANT__;

‎packages/shared/forks/ReactFeatureFlags.www.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const {
2525
enableObjectFiber,
2626
enableRetryLaneExpiration,
2727
enableTransitionTracing,
28-
enableTrustedTypesIntegration,
2928
retryLaneExpirationMs,
3029
syncLaneExpirationMs,
3130
transitionLaneExpirationMs,
@@ -45,7 +44,7 @@ export const enableProfilerTimer = __PROFILE__;
4544
exportconstenableProfilerCommitHooks=__PROFILE__;
4645
exportconstenableProfilerNestedUpdatePhase=__PROFILE__;
4746
exportconstenableUpdaterTracking=__PROFILE__;
48-
47+
exportconstenableTrustedTypesIntegration: boolean=true;
4948
exportconstenableSuspenseAvoidThisFallback: boolean=true;
5049

5150
exportconstenableAsyncDebugInfo: boolean=true;

0 commit comments

Comments
 (0)