# UI Pitfalls & Patterns
## Dropdown Stacking Context (z-index clipping)
**Symptom**: Service search dropdown (`#service-search-results`) is clipped/hidden by the quote summary section or accordion panels, despite `z-index: 99999 !important`.
**Root cause**: A parent element creates a stacking context (`overflow: hidden`, `transform`, `opacity < 1`, `will-change`). The dropdown's z-index is scoped within that parent and cannot escape. The accordion panels use `overflow: hidden` for collapse animations.
**Fix — Portal/teleport pattern** (applied in `main.js` and `quote-tab-manager.js`):
1. In `renderServiceResults()`, move dropdown to `#dropdown-root` on first open
2. Position with `position: fixed` + `getBoundingClientRect()` on search input
3. Add scroll/resize listeners to keep dropdown anchored to input
```js
// Before showing dropdown:
const dropdownRoot = document.getElementById('dropdown-root');
if (dropdownRoot && resultsEl.parentElement !== dropdownRoot) {
dropdownRoot.appendChild(resultsEl);
}
const rect = input.getBoundingClientRect();
resultsEl.style.position = 'fixed';
resultsEl.style.top = (rect.bottom + 4) + 'px';
resultsEl.style.left = rect.left + 'px';
resultsEl.style.width = rect.width + 'px';
// In initialization, add:
const reposition = () => {
if (resultsEl.classList.contains('hidden')) return;
const rect = input.getBoundingClientRect();
resultsEl.style.top = (rect.bottom + 4) + 'px';
resultsEl.style.left = rect.left + 'px';
resultsEl.style.width = rect.width + 'px';
};
window.addEventListener('scroll', reposition, { passive: true });
window.addEventListener('resize', reposition);
```
All pages have `#dropdown-root` at end of `
`: `index.html`, `dashboard.html`, `repair-orders.html`, `appointments.html`, `customers.html`.
## State Clearing Before RO Population
## React Custom Dropdown (v2)
When you need a styled dropdown that always opens below the trigger (native `