Custom Element Getrootnode.closest() Function Crossing Multiple (parent) Shadowdom Boundaries
I spent some time searching but have only seen too many regular 'walk the DOM' blogs or answers that only go one level UP with getRootnode() Pseudo code: HTML //#
Solution 1:
This does the same as .closest() from inside any child (shadow)DOM
but walking up the DOM crossing shadowroot Boundaries
Optimized for (extreme) minification
//declared as method on a Custom Element:closestElement(
selector, // selector like in .closest()
base = this, // extra functionality to skip a parent
__Closest = (el, found = el && el.closest(selector)) =>
!el || el === document || el === window
? null// standard .closest() returns null for non-found selectors also
: found
? found // found a selector INside this element
: __Closest(el.getRootNode().host) // recursion!! break out to parent DOM) {
return__Closest(base);
}
Note: the __Closest function is declared as 'parameter' to avoid an extra let
declaration... better for minification, and keeps your IDE from complaining
Called from inside a Custom Element:
<element-x>
//# shadow-root
<element-y>
<element-z>
//# shadow-rootlet container = this.closestElement('element-x');
</element-z>
</element-y>
</element-x>
Solution 2:
Excellent examples! Wanted to contribute a TypeScript version that has a minor difference -- it follows assignedSlot while traversing up the shadow roots, so you can find the closest matching element in a chain of nested, slotted custom elements. It's not the fanciest way to write the TypeScript, but it gets the job done.
closestElement(selector: string, base: Element = this) {
function__closestFrom(el: Element | Window | Document): Element {
if (!el || el === document || el === window) returnnull;
if ((el asSlotable).assignedSlot) el = (el asSlotable).assignedSlot;
let found = (el asElement).closest(selector);
return found
? found
: __closestFrom(((el asElement).getRootNode() asShadowRoot).host);
}
return__closestFrom(base);
}
The equvalent in JS is:
closestElement(selector, base = this) {
function__closestFrom(el) {
if (!el || el === document || el === window)
returnnull;
if (el.assignedSlot)
el = el.assignedSlot;
let found = el.closest(selector);
return found
? found
: __closestFrom(el.getRootNode().host);
}
return__closestFrom(base);
}
Solution 3:
Something like this should do the trick
functionclosestPassShadow(node, selector) {
if (!node) {
returnnull;
}
if (node instanceofShadowRoot) {
returnthis.closestPassShadow(node.host, selector);
}
if (node instanceofHTMLElement) {
if (node.matches(selector)) {
return node;
} else {
returnthis.closestPassShadow(node.parentNode, selector);
}
}
returnthis.closestPassShadow(node.parentNode, selector);
}
Post a Comment for "Custom Element Getrootnode.closest() Function Crossing Multiple (parent) Shadowdom Boundaries"