Fix labels becoming unclickable behind page overlays

Labels were inserted as normal DOM siblings with z-index set but
position left as the default "static" - z-index has no effect on
non-positioned elements, so any ancestor that establishes its own
stacking context (e.g. a position:relative logo wrapper with a
hover/link overlay, common in component libraries like Salesforce
LWC/SLDS) could paint over the label and swallow clicks intended for
it. Labels now get a real position:absolute anchored to the target
element's viewport position and are appended directly to
document.body, escaping any ancestor stacking context while still
scrolling correctly with the page.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Sascha 2026-07-13 11:56:15 +02:00
parent 7a73a68998
commit f9cfa1c91e
3 changed files with 16 additions and 7 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -192,9 +192,18 @@
color: colors.text color: colors.text
}); });
if (opts.position === 'absolute' && el.offsetParent && el.offsetParent !== document.body) { // Als Geschwisterknoten mit z-index eingefügte Labels bleiben "position: static"
style.left = `${el.offsetLeft}px`; // (z-index wirkt dort gar nicht) und können daher von jedem CSS-Overlay der
style.top = `${el.offsetTop}px`; // besuchten Seite verdeckt und unklickbar gemacht werden (z.B. position:relative-
// Wrapper mit eigenem Overlay, wie bei Logo-Containern üblich). Labels werden
// deshalb wirklich absolut positioniert und direkt an document.body gehängt
// das verlässt jeden Stacking-Context der Seite und bleibt beim Scrollen
// trotzdem an der richtigen Stelle, da die Koordinaten dokumentrelativ sind.
if (opts.position === 'absolute') {
const rect = el.getBoundingClientRect();
style.position = 'absolute';
style.left = `${rect.left + window.scrollX}px`;
style.top = `${rect.top + window.scrollY}px`;
} }
if (opts.extraStyle) Object.assign(style, opts.extraStyle); if (opts.extraStyle) Object.assign(style, opts.extraStyle);
@ -267,8 +276,8 @@
wrapper.className += ` ${NS}-global`; wrapper.className += ` ${NS}-global`;
} }
if (opts.position === 'absolute' && el.parentNode) { if (opts.position === 'absolute') {
el.parentNode.insertBefore(wrapper, el.nextSibling); document.body.appendChild(wrapper);
} else { } else {
(opts.insertInto || el.parentNode).appendChild(wrapper); (opts.insertInto || el.parentNode).appendChild(wrapper);
} }