Native JS equivalent to jQuery delegation

This should do it for you on a regular HTML element:

HTMLElement.prototype.on = function(event, selector, handler) {
    this.addEventListener(event, function(e) {
        let target =;
        if (typeof(selector) === 'string') {
            while (!target.matches(selector) && target !== this) {
                target = target.parentElement;

            if (target.matches(selector))
      , e);
        } else {
      , e);

What happens is basically this:

// $(document).on("click", <selector>, handler)
document.addEventListener("click", function(e) {
    for (var; target && target!=this; target=target.parentNode) {
    // loop parent nodes from the target to the delegation node
        if (target.matches(<selector>)) {
  , e);
}, false);

However, e.currentTarget is document when the handler is called, and e.stop[Immediate]Propagation() will work differently. jQuery abstracts over that (including call order) a lot.

I've used the .matches() method, which is not yet standard but already available under different names in modern browsers. You might use a custom predicate to test elements instead of a selector. And addEventListener is obviously not oldIE-compatible.