כשמעבירים רכיב פתוח של <dialog>, popover או מסך מלא ב-DOM באמצעות שיטות מסורתיות כמו appendChild() או insertBefore(), הדפדפן מסיר את הרכיב מה-DOM באופן משתמע ומכניס אותו מחדש. ההסרה הזו מאפסת את המצב, וגורמת לסגירה פתאומית של חלונות מודאליים, חלונות קופצים ואלמנטים במסך מלא.
כדי לשנות את ההורה של רכיבים בשכבה העליונה בלי להפריע לחוויית המשתמש או לסגור אותם, צריך להשתמש ב-API האטומי moveBefore().
העברת רכיבים פתוחים בשכבה העליונה להורה אחר
moveBefore() מקבל שני ארגומנטים: הצומת שצריך להעביר וצומת עזר להוספה לפני (או null להוספה בסוף של ההורה החדש).
const newParent = document.getElementById('new-container');
const dialogElement = document.getElementById('my-dialog');
// MANDATORY: Use moveBefore to ensure the <dialog> or popover stays open.
// Passing null appends it to the end of newParent.
newParent.moveBefore(dialogElement, null);
אסטרטגיות חלופיות
מכיוון ש-moveBefore() הוא שיפור הדרגתי (progressive enhancement), חובה להשתמש בזיהוי תכונות לפני שקוראים לו. בדפדפנים ישנים יותר, תצטרכו לחזור לשיטה המסורתית של שינוי רכיב ההורה.
חובה: ברכיבי <dialog> בדפדפנים לא נתמכים, המעבר הרגיל יסגור את תיבת הדו-שיח. אם אתם רוצים שהיא תישאר פתוחה, תצטרכו לפתוח אותה מחדש באופן ידני אחרי ההעברה.
const targetParent = document.getElementById('target-container');
const popoverOrDialog = document.getElementById('my-top-layer-element');
// Check if moveBefore is supported
if ('moveBefore' in Element.prototype) {
targetParent.moveBefore(popoverOrDialog, null);
} else {
// Fallback: traditional move.
// Note: This WILL close <dialog>, popover, and fullscreen elements.
const wasOpen = popoverOrDialog.hasAttribute('open') || popoverOrDialog.matches(':popover-open');
targetParent.insertBefore(popoverOrDialog, null);
// Manually restore state if possible
if (wasOpen && typeof popoverOrDialog.showModal === 'function') {
popoverOrDialog.showModal();
} else if (wasOpen && typeof popoverOrDialog.showPopover === 'function') {
popoverOrDialog.showPopover();
}
}