Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify bootstrapDelegationHandler using Element.closest #41116

Open
2 tasks done
frkly opened this issue Dec 21, 2024 · 0 comments
Open
2 tasks done

Simplify bootstrapDelegationHandler using Element.closest #41116

frkly opened this issue Dec 21, 2024 · 0 comments

Comments

@frkly
Copy link

frkly commented Dec 21, 2024

Prerequisites

Proposal

Hello Bootstrap team,

I have a suggestion to simplify and potentially optimize the bootstrapDelegationHandler function in event-handler.js.

Current Behavior

function bootstrapDelegationHandler(element, selector, fn) {
return function handler(event) {
const domElements = element.querySelectorAll(selector)
for (let { target } = event; target && target !== this; target = target.parentNode) {
for (const domElement of domElements) {
if (domElement !== target) {
continue
}
hydrateObj(event, { delegateTarget: target })
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn)
}
return fn.apply(target, [event])
}
}
}
}

The bootstrapDelegationHandler function is invoked when the third argument of the EventHandler.on method, handler, is a selector string. It is widely used to detect components like carousel, collapse, dropdown, modal, offcanvas, and tab based on their data attributes. In these cases, the first argument of bootstrapDelegationHandler, element, is typically set to document.

For example:

EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {

As a result, Bootstrap executes multiple DOM selector queries against the entire DOM tree every time an event is triggered to check if the event is related to a specific component. For instance, with click events in the default bundle (loading all components), this can result in 11 DOM queries, causing noticeable delays depending on the DOM tree size and the user's device.

Motivation and context

Proposed Implementation

I suggest replacing the current DOM traversal logic with the more efficient Element.closest method, which simplifies the implementation and improves performance. Here's the proposed code:

function bootstrapDelegationHandler(element, selector, fn) {
  return function handler(event) {
    const target = event.target.closest(selector);

    if (target && element.contains(target)) {
      hydrateObj(event, { delegateTarget: target });

      if (handler.oneOff) {
        EventHandler.off(element, event.type, selector, fn);
      }

      return fn.apply(target, [event]);
    }
  };
}

The Element.closest method is widely supported in modern browsers, aligning with Bootstrap's browser compatibility requirements.
https://caniuse.com/element-closest

If there are any potential side effects or edge cases I might have overlooked, I would greatly appreciate your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants