diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
index dafc4ff17eb22..96a8e93f84256 100644
--- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
+++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
@@ -1216,7 +1216,15 @@ export function canHydrateTextInstance(
if (text === '') return null;
while (instance.nodeType !== TEXT_NODE) {
- if (!inRootOrSingleton || !enableHostSingletons) {
+ if (
+ enableFormActions &&
+ instance.nodeType === ELEMENT_NODE &&
+ instance.nodeName === 'INPUT' &&
+ (instance: any).type === 'hidden'
+ ) {
+ // If we have extra hidden inputs, we don't mismatch. This allows us to
+ // embed extra form data in the original form.
+ } else if (!inRootOrSingleton || !enableHostSingletons) {
return null;
}
const nextInstance = getNextHydratableSibling(instance);
diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
index 8dfe93b9b534a..f574b16040b68 100644
--- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
+++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration-test.js
@@ -732,4 +732,23 @@ describe('ReactDOMServerHydration', () => {
expect(c.current.name).toBe('c');
expect(c.current.value).toBe('C');
});
+
+ // @gate enableFormActions
+ it('allows rendering extra hidden inputs immediately before a text instance', async () => {
+ const element = document.createElement('div');
+ element.innerHTML =
+ '';
+ const button = element.firstChild;
+ const ref = React.createRef();
+ const extraText = 'me';
+
+ await act(() => {
+ ReactDOMClient.hydrateRoot(
+ element,
+ ,
+ );
+ });
+
+ expect(ref.current).toBe(button);
+ });
});