Fix command palette results being unclickable

The backdrop div was nested inside .modal instead of rendered as its
sibling. Tabler/Bootstrap's backdrop (z-index 1050) is only supposed
to sit below the modal (z-index 1055) because normally they're both
direct children of the same stacking context; nesting it inside
.modal instead made it establish z-index inside .modal's own stacking
context, where it painted on top of .modal-dialog and silently
absorbed every click meant for a result row (confirmed via
elementFromPoint in a real browser: clicking a result hit
.modal-backdrop, not the result div). Moved the backdrop to be a
sibling rendered before .modal, matching the structure elementFromPoint
now confirms resolves to the actual result element.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
bobbanandClaude Sonnet 5 committed 2026-09-20 23:02:55 +02:00
1 parent 5c1376cf1c
commit 9c07718d2d
1 file changed
+52 -45
+52 -45
View File
@@ -192,57 +192,64 @@ export default function CommandPalette() {
let lastCategory = ""; let lastCategory = "";
return ( return (
<div className="modal modal-blur show" style={{ display: "block" }} onClick={() => setOpen(false)}> <>
<div className="modal-dialog modal-dialog-centered" style={{ maxWidth: 600 }} onClick={(e) => e.stopPropagation()}> {/* Rendered as a sibling, not a child, of .modal — Tabler/Bootstrap's z-index values
<div className="modal-content"> (backdrop 1050 vs modal 1055) only sort correctly when compared in the same
<div className="modal-body p-0"> stacking context. Nested inside .modal, the backdrop was created its own stacking
<div className="p-2 border-bottom"> context and painted on top of .modal-dialog, silently swallowing every click meant
<div className="input-icon"> for a result row. */}
<span className="input-icon-addon"> <div className="modal-backdrop show"></div>
<IconSearch size={18} /> <div className="modal modal-blur show" style={{ display: "block" }} onClick={() => setOpen(false)}>
</span> <div className="modal-dialog modal-dialog-centered" style={{ maxWidth: 600 }} onClick={(e) => e.stopPropagation()}>
<input <div className="modal-content">
ref={inputRef} <div className="modal-body p-0">
type="text" <div className="p-2 border-bottom">
className="form-control form-control-lg border-0" <div className="input-icon">
placeholder="Search servers, DNS, secrets, IPs, integrations…" <span className="input-icon-addon">
value={query} <IconSearch size={18} />
onChange={(e) => setQuery(e.target.value)} </span>
onKeyDown={handleInputKeyDown} <input
/> ref={inputRef}
type="text"
className="form-control form-control-lg border-0"
placeholder="Search servers, DNS, secrets, IPs, integrations…"
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyDown={handleInputKeyDown}
/>
</div>
</div> </div>
</div> <div style={{ maxHeight: "60vh", overflowY: "auto" }}>
<div style={{ maxHeight: "60vh", overflowY: "auto" }}> {loading && <div className="p-3 text-secondary">Searching…</div>}
{loading && <div className="p-3 text-secondary">Searching…</div>} {!loading && query.trim().length >= 2 && items.length === 0 && <div className="p-3 text-secondary">No matches.</div>}
{!loading && query.trim().length >= 2 && items.length === 0 && <div className="p-3 text-secondary">No matches.</div>} {!loading && query.trim().length < 2 && <div className="p-3 text-secondary">Type at least 2 characters…</div>}
{!loading && query.trim().length < 2 && <div className="p-3 text-secondary">Type at least 2 characters…</div>} {items.map((item, index) => {
{items.map((item, index) => { const showHeader = item.category !== lastCategory;
const showHeader = item.category !== lastCategory; lastCategory = item.category;
lastCategory = item.category; return (
return ( <div key={item.key}>
<div key={item.key}> {showHeader && (
{showHeader && ( <div className="px-3 pt-2 pb-1 text-uppercase text-secondary" style={{ fontSize: "0.7rem" }}>
<div className="px-3 pt-2 pb-1 text-uppercase text-secondary" style={{ fontSize: "0.7rem" }}> {item.category}
{item.category} </div>
)}
<div
className={`px-3 py-2 d-flex justify-content-between align-items-center gap-3 ${index === activeIndex ? "bg-secondary-lt" : ""}`}
style={{ cursor: "pointer" }}
onMouseEnter={() => setActiveIndex(index)}
onClick={() => go(item)}
>
<div className="text-truncate">{item.title}</div>
{item.subtitle && <div className="text-secondary small text-truncate">{item.subtitle}</div>}
</div> </div>
)}
<div
className={`px-3 py-2 d-flex justify-content-between align-items-center gap-3 ${index === activeIndex ? "bg-secondary-lt" : ""}`}
style={{ cursor: "pointer" }}
onMouseEnter={() => setActiveIndex(index)}
onClick={() => go(item)}
>
<div className="text-truncate">{item.title}</div>
{item.subtitle && <div className="text-secondary small text-truncate">{item.subtitle}</div>}
</div> </div>
</div> );
); })}
})} </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="modal-backdrop show"></div> </>
</div>
); );
} }