diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
index bcc4ad72a8b34..3381005cf5c23 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
@@ -116,6 +116,10 @@ describe('ReactDOMFizzServer', () => {
               // We assume this is a React added ID that's a non-visual implementation detail.
               continue;
             }
+            if (attributes[i].name === 'data-reactroot') {
+              // We ignore React injected attributes.
+              continue;
+            }
             props[attributes[i].name] = attributes[i].value;
           }
           props.children = getVisibleChildren(node);
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
index a61727d7fdf04..f805854841ffa 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerBrowser-test.js
@@ -55,7 +55,9 @@ describe('ReactDOMFizzServer', () => {
       
hello world
,
     );
     const result = await readResult(stream);
-    expect(result).toMatchInlineSnapshot(`"hello world
"`);
+    expect(result).toMatchInlineSnapshot(
+      `"hello world
"`,
+    );
   });
 
   // @gate experimental
@@ -94,7 +96,7 @@ describe('ReactDOMFizzServer', () => {
 
     const result = await readResult(stream);
     expect(result).toMatchInlineSnapshot(
-      `"Done
"`,
+      `"Done
"`,
     );
   });
 
diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
index dcef8c2406a6c..cd93ac5a5163c 100644
--- a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js
@@ -66,7 +66,7 @@ describe('ReactDOMFizzServer', () => {
     startWriting();
     jest.runAllTimers();
     expect(output.result).toMatchInlineSnapshot(
-      `"hello world
"`,
+      `"hello world
"`,
     );
   });
 
@@ -84,7 +84,7 @@ describe('ReactDOMFizzServer', () => {
     // Then React starts writing.
     startWriting();
     expect(output.result).toMatchInlineSnapshot(
-      `"testhello world
"`,
+      `"testhello world
"`,
     );
   });
 
@@ -132,7 +132,7 @@ describe('ReactDOMFizzServer', () => {
     // Then React starts writing.
     startWriting();
     expect(output.result).toMatchInlineSnapshot(
-      `"testDone
"`,
+      `"testDone
"`,
     );
   });
 
diff --git a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
index acc6e86879c81..62d27c5e99174 100644
--- a/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
+++ b/packages/react-dom/src/server/ReactDOMServerFormatConfig.js
@@ -32,6 +32,7 @@ import {
   OVERLOADED_BOOLEAN,
   NUMERIC,
   POSITIVE_NUMERIC,
+  ROOT_ATTRIBUTE_NAME,
 } from '../shared/DOMProperty';
 import {isUnitlessNumber} from '../shared/CSSProperty';
 
@@ -63,6 +64,7 @@ export type ResponseState = {
   sentCompleteSegmentFunction: boolean,
   sentCompleteBoundaryFunction: boolean,
   sentClientRenderFunction: boolean,
+  hasEmittedRoot: boolean,
 };
 
 // Allows us to keep track of what we've already written so we can refer back to it.
@@ -79,6 +81,7 @@ export function createResponseState(
     sentCompleteSegmentFunction: false,
     sentCompleteBoundaryFunction: false,
     sentClientRenderFunction: false,
+    hasEmittedRoot: false,
   };
 }
 
@@ -99,7 +102,7 @@ type InsertionMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
 
 // Lets us keep track of contextual state and pick it back up after suspending.
 export type FormatContext = {
-  insertionMode: InsertionMode, // root/svg/html/mathml/table
+  insertionMode: InsertionMode, // svg/html/mathml/table
   selectedValue: null | string | Array, // the selected value(s) inside a