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
<element-x>
//# shadow-root
    <element-y>
        <element-z>
        //# shadow-root
        let container = this.closest('element-x');
        </element-z>
    </element-y>
</element-x>
The standard element.closest() function does not pierce shadow boundaries;
So this.closest('element-x') returns null because there is no <element-x> within <element-z> shadowDom
Goal:
Find <element-x> from inside descendant <element z> (any nested level)
Required:
A (recursive) .closest() function that walks up the (shadow) DOMs and finds <element-x>
Note: elements may or may not have ShadowDOM (see <element y>: only lightDOM)
I can and will do it myself tomorrow; just wondered if some bright mind had already done it.
Resources:
- https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode
- https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/host
Update
This is the UNminified code from the answer below:
        closestElement(selector, base = this) {
            function __closestFrom(el) {
                if (!el || el === document || el === window) return null;
                let found = el.closest(selector);
                if (found)
                  return found;
                else
                  __closestFrom(el.getRootNode().host);
            }
            return __closestFrom(base);
        }
Update #2
I changed it to a method on my BaseElement:
  closestElement(selector, el = this) {
    return (
      (el && el != document && el != window && el.closest(selector)) ||
      this.closestElement(selector, el.getRootNode().host)
    );
  }
Events
As Intervalia comments; yes Events are another solution.
But then... an Event needs to be attached to an ancestor... How to know which ancestor to use?
 
     
     
     
    