[Fiber] Don't warn when rendering data block scripts (#35953)
Sebastian "Sebbie" Silbermann committed
Mar 3, 2026 at 19:38 UTC
e6f1c33acf81d9865863ab149d24726f43a56db0
2 files changed
+66
-1
packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
+46
-1
@@ -183,6 +183,7 @@ export type Props = {
183
checked?: boolean,
184
defaultChecked?: boolean,
185
multiple?: boolean,
186
+ type?: string,
187
src?: string | Blob | MediaSource | MediaStream, // TODO: Response
188
srcSet?: string,
189
loading?: 'eager' | 'lazy',
@@ -469,6 +470,44 @@ export function createHoistableInstance(
470
}
471
472
let didWarnScriptTags = false;
473
+function isScriptDataBlock(props: Props): boolean {
474
+ const scriptType = props.type;
475
+ if (typeof scriptType !== 'string' || scriptType === '') {
476
+ return false;
477
+ }
478
+ const lower = scriptType.toLowerCase();
479
+ // Special non-MIME keywords recognized by the HTML spec
480
+ // TODO: May be fine to also not warn about having these types be parsed as "parser-inserted"
481
+ if (
482
+ lower === 'module' ||
483
+ lower === 'importmap' ||
484
+ lower === 'speculationrules'
485
+ ) {
486
+ return false;
487
+ }
488
+ // JavaScript MIME types per https://mimesniff.spec.whatwg.org/#javascript-mime-type
489
+ switch (lower) {
490
+ case 'application/ecmascript':
491
+ case 'application/javascript':
492
+ case 'application/x-ecmascript':
493
+ case 'application/x-javascript':
494
+ case 'text/ecmascript':
495
+ case 'text/javascript':
496
+ case 'text/javascript1.0':
497
+ case 'text/javascript1.1':
498
+ case 'text/javascript1.2':
499
+ case 'text/javascript1.3':
500
+ case 'text/javascript1.4':
501
+ case 'text/javascript1.5':
502
+ case 'text/jscript':
503
+ case 'text/livescript':
504
+ case 'text/x-ecmascript':
505
+ case 'text/x-javascript':
506
+ return false;
507
+ }
508
+ // Any other non-empty type value means this is a data block
509
+ return true;
510
+}
511
const warnedUnknownTags: {
512
[key: string]: boolean,
513
} = {
@@ -526,7 +565,13 @@ export function createInstance(
565
// set to true and it does not execute
566
const div = ownerDocument.createElement('div');
567
if (__DEV__) {
529
- if (enableTrustedTypesIntegration && !didWarnScriptTags) {
568
+ if (
569
+ enableTrustedTypesIntegration &&
570
+ !didWarnScriptTags &&
571
+ // Data block scripts are not executed by UAs anyway so
572
+ // we don't need to warn: https://html.spec.whatwg.org/multipage/scripting.html#attr-script-type
573
+ !isScriptDataBlock(props)
574
+ ) {
575
console.error(
576
'Encountered a script tag while rendering React component. ' +
577
'Scripts inside React components are never executed when rendering ' +
packages/react-dom/src/client/__tests__/trustedTypes-test.internal.js
+20
@@ -248,4 +248,24 @@ describe('when Trusted Types are available in global object', () => {
248
root.render(<script>alert("I am not executed")</script>);
249
});
250
});
251
+
252
+ it('should not warn when rendering a data block script tag', async () => {
253
+ const root = ReactDOMClient.createRoot(container);
254
+ await act(() => {
255
+ root.render(
256
+ <script type="application/json">{'{"key": "value"}'}</script>,
257
+ );
258
+ });
259
+ });
260
+
261
+ it('should not warn when rendering a ld+json script tag', async () => {
262
+ const root = ReactDOMClient.createRoot(container);
263
+ await act(() => {
264
+ root.render(
265
+ <script type="application/ld+json">
266
+ {'{"@context": "https://schema.org"}'}
267
+ </script>,
268
+ );
269
+ });
270
+ });
271
});