{"record":{"id":"66e787ea6b1da833","repo":"facebook/react","slug":"startgesturetransition-required-cloning-a-s-e","errorCode":null,"errorMessage":"startGestureTransition() required cloning a <%s> element since it exists in both states of the gesture. This can be problematic since it will load it twice Try removing or hiding it with <Activity mode=\"offscreen\"> in the optimistic state.","messagePattern":"startGestureTransition\\(\\) required cloning a <(.+?)> element since it exists in both states of the gesture\\. This can be problematic since it will load it twice Try removing or hiding it with <Activity mode=\"offscreen\"> in the optimistic state\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js","lineNumber":682,"sourceCode":"}\n\nlet didWarnForClone = false;\n\nexport function cloneMutableInstance(\n  instance: Instance,\n  keepChildren: boolean,\n): Instance {\n  if (__DEV__) {\n    // Warn for problematic\n    const tagName = instance.tagName;\n    switch (tagName) {\n      case 'VIDEO':\n      case 'IFRAME':\n        if (!didWarnForClone) {\n          didWarnForClone = true;\n          // TODO: Once we have the ability to avoid cloning the root, suggest an absolutely\n          // positioned ViewTransition instead as the solution.\n          console.warn(\n            'startGestureTransition() required cloning a <%s> element since it exists in ' +\n              'both states of the gesture. This can be problematic since it will load it twice ' +\n              'Try removing or hiding it with <Activity mode=\"offscreen\"> in the optimistic state.',\n            tagName.toLowerCase(),\n          );\n        }\n        break;\n    }\n  }\n  return instance.cloneNode(keepChildren);\n}\n\nexport function appendInitialChild(\n  parentInstance: Instance,\n  child: Instance | TextInstance,\n): void {\n  // Note: This should not use moveBefore() because initial are appended while disconnected.\n  parentInstance.appendChild(child);","sourceCodeStart":664,"sourceCodeEnd":700,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js#L664-L700","documentation":"During a gesture-driven View Transition (startGestureTransition / <ViewTransition> optimistic updates), react-dom must keep both the current and optimistic state mounted; when a DOM node exists in both states it is cloned via cloneInstance (packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js:682). Cloning <video> or <iframe> is expensive and semantically wrong — the media loads twice and playback state diverges — so react-dom warns once per session (didWarnForClone) telling you to remove the element from one state or hide it with <Activity mode=\"offscreen\">. The clone still happens; this is a performance/correctness warning, not a failure.","triggerScenarios":"A gesture transition (e.g. useSwipeTransition / startGestureTransition optimistic state) where the same <video> or <iframe> persists in both the pre-gesture and optimistic trees without an Activity boundary, forcing react-dom to clone it so both states render simultaneously.","commonSituations":"Gesture-driven page transitions (swipe navigation) over media players or embedded maps/videos; optimistic UI that keeps the same keyed media element across states; enabling View Transitions on routes that contain iframes.","solutions":["Wrap the <video>/<iframe> in <Activity mode=\"offscreen\"> in the optimistic state so it is hidden rather than duplicated.","Remove the element from the optimistic tree if it does not need to be visible during the gesture.","If duplication is acceptable, ignore the one-time warning but verify playback/scroll position still behaves after the transition.","As an alternative, key the media element differently across states and animate it with an absolutely positioned ViewTransition instead of relying on cloning."],"exampleFix":"// before\nfunction OptimisticState() {\n  return <video src=\"/movie.mp4\" controls />;\n}\n\n// after\nfunction OptimisticState() {\n  return (\n    <Activity mode=\"offscreen\">\n      <video src=\"/movie.mp4\" controls />\n    </Activity>\n  );\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Wrap persistent <video>/<iframe> elements in <Activity mode=\"offscreen\"> in the optimistic gesture state.","Keep media elements out of one of the two gesture states when they do not need to be visible.","Remember the warning fires only once per session (didWarnForClone), so audit all media elements up front."],"tags":["react-dom","view-transitions","gesture-transitions","media-elements","dev-only"],"backgroundTag":"view-transition-cloning","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}