Files
hermes-config/skills/self-hosting/shop-pro-quote/references/dropdown-teleport.md
T
2026-07-12 10:17:17 -04:00

2.0 KiB

Dropdown Teleport Pattern

Problem

The #service-search-results dropdown lives inside #services-content, an accordion section with overflow: hidden. Even with z-index: 99999 !important, it's clipped by the parent stacking context and hidden behind the Quote Summary section.

Fix: Teleport to #dropdown-root

Every page has a <div id="dropdown-root"></div> at the end of <body>. When the dropdown opens, move it there and position it with position: fixed + getBoundingClientRect().

In renderServiceResults() (both main.js and quote-tab-manager.js):

// Teleport to dropdown-root to escape stacking context clipping
const dropdownRoot = document.getElementById('dropdown-root');
const serviceSearchInput = document.getElementById('service-search-input');
if (dropdownRoot && serviceSearchResults.parentElement !== dropdownRoot) {
    dropdownRoot.appendChild(serviceSearchResults);
}
// Position relative to the input
if (serviceSearchInput) {
    const rect = serviceSearchInput.getBoundingClientRect();
    serviceSearchResults.style.position = 'fixed';
    serviceSearchResults.style.top = (rect.bottom + 4) + 'px';
    serviceSearchResults.style.left = rect.left + 'px';
    serviceSearchResults.style.width = rect.width + 'px';
}

Scroll/resize repositioning (in initializeServiceSearch / attachMainEventListeners):

const repositionDropdown = () => {
    if (serviceSearchResults.classList.contains('hidden')) return;
    const rect = serviceSearchInput.getBoundingClientRect();
    serviceSearchResults.style.top = (rect.bottom + 4) + 'px';
    serviceSearchResults.style.left = rect.left + 'px';
    serviceSearchResults.style.width = rect.width + 'px';
};
window.addEventListener('scroll', repositionDropdown, { passive: true });
window.addEventListener('resize', repositionDropdown);

Files Modified

  • main.jsrenderServiceResults() + attachMainEventListeners()
  • quote-tab-manager.jsrenderServiceResults() + initializeServiceSearch()