Mueve el elemento del DOM sin perder el estado

Funciones web: moveBefore()

Cuando se cambia el elemento superior de los elementos del DOM con métodos tradicionales, como appendChild() o insertBefore(), el navegador quita implícitamente el elemento del DOM y, luego, lo inserta en su nueva ubicación. Esta operación de "quitar e insertar" restablece muchos estados internos, lo que hace que se vuelvan a cargar los elementos <iframe>, se reinicien las animaciones de CSS y los campos de entrada pierdan el enfoque.

Para mover un elemento y conservar su estado, usa la API de moveBefore(). Este método realiza un movimiento atómico, omitiendo por completo los pasos de eliminación e inserción.

Cómo mover un elemento con estado

Usa moveBefore() exactamente como usarías insertBefore(). Requiere dos argumentos: el nodo que se moverá y un nodo de referencia para insertarlo antes (o null para agregarlo al final del nuevo elemento superior).

const newParent = document.getElementById('new-parent');
const elementWithState = document.getElementById('iframe-or-focused-input');

// MANDATORY: Use moveBefore to preserve state. 
// Passing null as the second argument appends the element to the end of newParent.
newParent.moveBefore(elementWithState, null);

Mover elementos personalizados (componentes web)

Si mueves elementos personalizados con moveBefore(), no se activarán sus métodos de ciclo de vida connectedCallback ni disconnectedCallback.

Si tu elemento personalizado necesita ejecutar una lógica específica cuando se mueve, implementa el método connectedMoveCallback() dentro de la definición del elemento personalizado.

class MyCustomElement extends HTMLElement {
  connectedCallback() {
    // Runs on initial insertion.
  }
  
  connectedMoveCallback() {
    // Runs when the element is moved via moveBefore().
    // Use this to update state that depends on the new DOM location.
  }
}

Estrategias de resguardo

Dado que moveBefore() es una mejora progresiva, DEBES usar la detección de funciones antes de llamarla, recurriendo a las operaciones tradicionales de insertBefore() o appendChild() para los navegadores más antiguos.

const targetParent = document.getElementById('target-container');
const nodeToMove = document.getElementById('moving-element');

// Check if moveBefore is supported on the Element prototype
if ('moveBefore' in Element.prototype) {
  targetParent.moveBefore(nodeToMove, null);
} else {
  // Fallback: traditional move. 
  // Note: This WILL reset <iframe>, animation, and focus state in unsupported browsers.
  targetParent.insertBefore(nodeToMove, null);
}