element-closest

Lightweight polyfill for Element.closest and Element.matches

Library
npm
v3.0.2
352stars
CC0-1.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
35/100Needs Attention
Development Activity0
Maintenance0
Community60
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
58/100Fair
Architecture55
Code Quality55
Innovation40
Learning Curve80

element-closest is a tiny polyfill that brings the DOM standard Element.closest() and Element.matches() methods to browsers that don’t support them natively, at roughly 257 bytes gzipped. closest() walks up the DOM tree from an element and returns the nearest ancestor (or the element itself) matching a CSS selector, which is a common building block for event delegation patterns.

The polyfill is applied by calling the exported function with a window reference, so it works equally in a <script> tag include or bundled via Browserify/Webpack in a Node-based build. It checks for existing vendor-prefixed matches implementations (msMatchesSelector, mozMatchesSelector, webkitMatchesSelector) before falling back to its own selector-matching implementation, and only defines closest if the browser doesn’t already provide it natively.

What You Get

  • A drop-in polyfill for Element.prototype.closest() per the DOM standard
  • A drop-in polyfill for Element.prototype.matches(), including vendor-prefix detection
  • Both a browser <script> build and a Node/bundler-friendly CommonJS/ESM build
  • A sub-1KB footprint (428 bytes raw, ~257 bytes gzipped)
  • No-op behavior when native support already exists, so it’s always safe to include

Common Use Cases

  • Supporting event delegation (event.target.closest(selector)) in legacy browsers like IE8-11
  • Adding safe Element.matches() support without manually checking vendor prefixes
  • Shipping a minimal DOM polyfill bundle for older enterprise or embedded browser targets

Under The Hood

Architecture The entire implementation is a single exported polyfill(window) function in src/index.js: it first ensures Element.prototype.matches exists (falling back through vendor-prefixed variants, or implementing it manually by scanning querySelectorAll results), then defines Element.prototype.closest as a simple ancestor-walking loop that calls element.matches(selector) at each step until it finds a match or runs out of ancestors (nodeType !== 1). Tech Stack Authored in ES2015+ JavaScript and built with Rollup into three output formats: a UMD/global browser.js for <script> tag usage, a CommonJS index.js for Node/bundler usage, and an ESM index.mjs, with Babel used only for the browser build target. Code Quality The project’s only automated check is eslint src/*.js run via a pre-commit hook and as the test script — there is a test/test.js file present, but the primary quality gate is linting rather than an assertion-based test suite; this is a reasonable tradeoff given the tiny, single-function scope. API Design The polyfill is invoked explicitly with a window argument (elementClosest(window)) rather than auto-applying on import, which makes it SSR-safe and avoids surprising global side effects when bundled; consumers using the raw browser script get patching applied automatically on load instead.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search