New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@asamuzakjp/dom-selector

Package Overview
Dependencies
Maintainers
1
Versions
194
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@asamuzakjp/dom-selector

A CSS selector engine.

  • 6.4.2
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
243K
decreased by-34.3%
Maintainers
1
Weekly downloads
 
Created
Source

DOM Selector

build CodeQL npm (scoped)

A CSS selector engine.

Install

npm i @asamuzakjp/dom-selector

Usage

import { DOMSelector } from '@asamuzakjp/dom-selector';
import { JSDOM } from 'jsdom';

const { window } = new JSDOM();
const {
  closest, matches, querySelector, querySelectorAll
} = new DOMSelector(window);

matches(selector, node, opt)

matches - equivalent to Element.matches()

Parameters
  • selector string CSS selector
  • node object Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns boolean true if matched, false otherwise

closest(selector, node, opt)

closest - equivalent to Element.closest()

Parameters
  • selector string CSS selector
  • node object Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns object? matched node

querySelector(selector, node, opt)

querySelector - equivalent to Document.querySelector(), DocumentFragment.querySelector() and Element.querySelector()

Parameters
  • selector string CSS selector
  • node object Document, DocumentFragment or Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns object? matched node

querySelectorAll(selector, node, opt)

querySelectorAll - equivalent to Document.querySelectorAll(), DocumentFragment.querySelectorAll() and Element.querySelectorAll()
NOTE: returns Array, not NodeList

Parameters
  • selector string CSS selector
  • node object Document, DocumentFragment or Element node
  • opt object? options
    • opt.noexcept boolean? no exception
    • opt.warn boolean? console warn e.g. unsupported pseudo-class

Returns Array<(object | undefined)> array of matched nodes

Monkey patch jsdom

import { DOMSelector } from '@asamuzakjp/dom-selector';
import { JSDOM } from 'jsdom';

const dom = new JSDOM('', {
  runScripts: 'dangerously',
  url: 'http://localhost/',
  beforeParse: window => {
    const domSelector = new DOMSelector(window);

    const matches = domSelector.matches.bind(domSelector);
    window.Element.prototype.matches = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return matches(selector, this);
    };

    const closest = domSelector.closest.bind(domSelector);
    window.Element.prototype.closest = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return closest(selector, this);
    };

    const querySelector = domSelector.querySelector.bind(domSelector);
    window.Document.prototype.querySelector = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelector(selector, this);
    };
    window.DocumentFragment.prototype.querySelector = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelector(selector, this);
    };
    window.Element.prototype.querySelector = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelector(selector, this);
    };

    const querySelectorAll = domSelector.querySelectorAll.bind(domSelector);
    window.Document.prototype.querySelectorAll = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelectorAll(selector, this);
    };
    window.DocumentFragment.prototype.querySelectorAll = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelectorAll(selector, this);
    };
    window.Element.prototype.querySelectorAll = function (...args) {
      if (!args.length) {
        throw new window.TypeError('1 argument required, but only 0 present.');
      }
      const [selector] = args;
      return querySelectorAll(selector, this);
    };
  }
});

Supported CSS selectors

PatternSupportedNote
*
ns|E
*|E
|E
E
E:not(s1, s2, …)
E:is(s1, s2, …)
E:where(s1, s2, …)
E:has(rs1, rs2, …)
E.warning
E#myid
E[foo]
E[foo="bar"]
E[foo="bar" i]
E[foo="bar" s]
E[foo~="bar"]
E[foo^="bar"]
E[foo$="bar"]
E[foo*="bar"]
E[foo|="en"]
E:definedPartially supportedMatching with MathML is not yet supported.
E:dir(ltr)
E:lang(en)
E:any‑link
E:link
E:visitedReturns false or null to prevent fingerprinting.
E:local‑link
E:target
E:target‑within
E:scope
E:currentUnsupported
E:current(s)Unsupported
E:pastUnsupported
E:futureUnsupported
E:active
E:hover
E:focus
E:focus‑within
E:focus‑visible
E:open
E:closed
Partially supportedMatching with <select>, e.g. select:open, is not supported.
E:enabled
E:disabled
E:read‑write
E:read‑only
E:placeholder‑shown
E:default
E:checked
E:indeterminate
E:valid
E:invalid
E:required
E:optional
E:blankUnsupported
E:user‑valid
E:user‑invalid
Unsupported
E:root
E:empty
E:nth‑child(n [of S]?)
E:nth‑last‑child(n [of S]?)
E:first‑child
E:last‑child
E:only‑child
E:nth‑of‑type(n)
E:nth‑last‑of‑type(n)
E:first‑of‑type
E:last‑of‑type
E:only‑of‑type
E F
E > F
E + F
E ~ F
F || EUnsupported
E:nth‑col(n)Unsupported
E:nth‑last‑col(n)Unsupported
E:popover-open
E:state(v)*1
:host
:host(s)
:host‑context(s)
:host(:state(v))*1
:host:has(rs1, rs2, ...)
:host(s):has(rs1, rs2, ...)
:host‑context(s):has(rs1, rs2, ...)
&Only supports outermost &, i.e. equivalent to :scope

*1: ElementInternals.states, i.e. CustomStateSet, is not implemented in jsdom, so you need to apply a patch in the custom element constructor.

class LabeledCheckbox extends window.HTMLElement {
  #internals;
  constructor() {
    super();
    this.#internals = this.attachInternals();
    // patch CustomStateSet
    if (!this.#internals.states) {
      this.#internals.states = new Set();
    }
    this.addEventListener('click', this._onClick.bind(this));
  }
  get checked() {
    return this.#internals.states.has('checked');
  }
  set checked(flag) {
    if (flag) {
      this.#internals.states.add('checked');
    } else {
      this.#internals.states.delete('checked');
    }
  }
  _onClick(event) {
    this.checked = !this.checked;
  }
}

Performance

See benchmark for the latest results.

F: Failed because the selector is not supported or the result was incorrect.

matches()

Selectorjsdom v26.0.0 (nwsapi)happy-domlinkeDompatched-jsdom (dom-selector)Result
simple selector:
matches('.content')
112,297 ops/sec ±4.41%403,800 ops/sec ±2.26%9,352 ops/sec ±1.18%109,587 ops/sec ±0.36%happydom is the fastest and 3.7 times faster than patched-jsdom. jsdom is 1.0 times faster than patched-jsdom.
compound selector:
matches('p.content[id]:is(:last-child, :only-child)')
102,156 ops/sec ±0.83%403,804 ops/sec ±0.91%9,051 ops/sec ±0.78%77,568 ops/sec ±4.06%happydom is the fastest and 5.2 times faster than patched-jsdom. jsdom is 1.3 times faster than patched-jsdom.
compound selector:
matches('p.content[id]:is(:invalid-nth-child, :only-child)')
F387,515 ops/sec ±4.34%F41,904 ops/sec ±1.57%happydom is the fastest and 9.2 times faster than patched-jsdom.
compound selector:
matches('p.content[id]:not(:is(.foo, .bar))')
97,333 ops/sec ±0.62%394,134 ops/sec ±2.82%8,821 ops/sec ±0.86%79,436 ops/sec ±0.69%happydom is the fastest and 5.0 times faster than patched-jsdom. jsdom is 1.2 times faster than patched-jsdom.
complex selector:
matches('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner > .content')
63,065 ops/sec ±0.95%F5,751 ops/sec ±0.73%57,917 ops/sec ±1.27%jsdom is the fastest and 1.1 times faster than patched-jsdom.
complex selector:
matches('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner:has(> .content)')
29,609 ops/sec ±1.68%F5,741 ops/sec ±1.12%39,522 ops/sec ±3.55%patched-jsdom is the fastest. patched-jsdom is 1.3 times faster than jsdom.
complex selector within logical pseudo-class:
matches(':is(.box > .content, .block > .content)')
89,634 ops/sec ±0.66%F6,049 ops/sec ±0.33%83,881 ops/sec ±0.70%jsdom is the fastest and 1.1 times faster than patched-jsdom.
nested and chained :not() selector:
matches('p:not(:is(:not(.content))):not(.foo)')
F377,155 ops/sec ±1.07%6,087 ops/sec ±0.70%60,032 ops/sec ±26.27%happydom is the fastest and 6.3 times faster than patched-jsdom.

closest()

Selectorjsdom v26.0.0 (nwsapi)happy-domlinkeDompatched-jsdom (dom-selector)Result
simple selector:
closest('.container')
68,204 ops/sec ±1.82%266,567 ops/sec ±40.99%9,268 ops/sec ±0.81%82,517 ops/sec ±0.79%happydom is the fastest and 3.2 times faster than patched-jsdom. patched-jsdom is 1.2 times faster than jsdom.
compound selector:
closest('div.container[id]:not(.foo, .box)')
60,091 ops/sec ±0.56%F8,418 ops/sec ±1.06%51,243 ops/sec ±0.74%jsdom is the fastest and 1.2 times faster than patched-jsdom.
complex selector:
closest('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner > .content')
59,694 ops/sec ±0.61%F5,801 ops/sec ±0.69%53,569 ops/sec ±0.65%jsdom is the fastest and 1.1 times faster than patched-jsdom.
complex selector:
closest('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner:has(> .content)')
22,696 ops/sec ±0.97%F5,800 ops/sec ±0.52%34,907 ops/sec ±1.00%patched-jsdom is the fastest. patched-jsdom is 1.5 times faster than jsdom.
complex selector within logical pseudo-class:
closest(':is(.container > .content, .container > .box)')
68,572 ops/sec ±0.55%338,382 ops/sec ±1.46%5,985 ops/sec ±1.24%64,454 ops/sec ±0.49%happydom is the fastest and 5.2 times faster than patched-jsdom. jsdom is 1.1 times faster than patched-jsdom.
nested and chained :not() selector:
closest('div:not(:is(:not(.container))):not(.box)')
FF8,638 ops/sec ±0.52%55,838 ops/sec ±34.28%patched-jsdom is the fastest.

querySelector()

Selectorjsdom v26.0.0 (nwsapi)happy-domlinkeDompatched-jsdom (dom-selector)Result
simple selector:
querySelector('.content')
15,912 ops/sec ±2.11%307,120 ops/sec ±26.93%10,595 ops/sec ±0.99%71,245 ops/sec ±1.77%happydom is the fastest and 4.3 times faster than patched-jsdom. patched-jsdom is 4.5 times faster than jsdom.
compound selector:
querySelector('p.content[id]:is(:last-child, :only-child)')
7,333 ops/sec ±0.86%290,078 ops/sec ±42.38%9,955 ops/sec ±1.82%34,346 ops/sec ±1.15%happydom is the fastest and 8.4 times faster than patched-jsdom. patched-jsdom is 4.7 times faster than jsdom.
complex selector:
querySelector('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner > .content')
123 ops/sec ±1.40%F1,021 ops/sec ±0.53%553 ops/sec ±1.99%linkedom is the fastest and 1.8 times faster than patched-jsdom. patched-jsdom is 4.5 times faster than jsdom.
complex selector:
querySelector('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner:has(> .content)')
40.29 ops/sec ±6.51%F1,304 ops/sec ±0.87%382 ops/sec ±1.12%linkedom is the fastest and 3.4 times faster than patched-jsdom. patched-jsdom is 9.5 times faster than jsdom.
complex selector within logical pseudo-class:
querySelector(':is(.box > .content, .block > .content)')
2,104 ops/sec ±0.69%F9,762 ops/sec ±0.68%67,358 ops/sec ±0.69%patched-jsdom is the fastest. patched-jsdom is 32.0 times faster than jsdom.
nested and chained :not() selector:
querySelector('p:not(:is(:not(.content))):not(.foo)')
F354,191 ops/sec ±1.43%9,950 ops/sec ±0.86%65,426 ops/sec ±0.91%happydom is the fastest and 5.4 times faster than patched-jsdom.

querySelectorAll()

Selectorjsdom v26.0.0 (nwsapi)happy-domlinkeDompatched-jsdom (dom-selector)Result
simple selector:
querySelectorAll('.content')
938 ops/sec ±1.61%285 ops/sec ±3.27%993 ops/sec ±2.52%794 ops/sec ±37.70%linkedom is the fastest and 1.3 times faster than patched-jsdom. jsdom is 1.2 times faster than patched-jsdom.
compound selector:
querySelectorAll('p.content[id]:is(:last-child, :only-child)')
331 ops/sec ±2.79%320 ops/sec ±4.68%949 ops/sec ±0.89%354 ops/sec ±26.10%linkedom is the fastest and 2.7 times faster than patched-jsdom. patched-jsdom is 1.1 times faster than jsdom.
complex selector:
querySelectorAll('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner > .content')
125 ops/sec ±0.67%F298 ops/sec ±0.85%140 ops/sec ±1.03%linkedom is the fastest and 2.1 times faster than patched-jsdom. patched-jsdom is 1.1 times faster than jsdom.
complex selector:
querySelectorAll('.box:first-child ~ .box:nth-of-type(4n+1) + .box[id] .block.inner:has(> .content)')
42.34 ops/sec ±0.89%F351 ops/sec ±0.89%135 ops/sec ±1.36%linkedom is the fastest and 2.6 times faster than patched-jsdom. patched-jsdom is 3.2 times faster than jsdom.
complex selector within logical pseudo-class:
querySelectorAll(':is(.box > .content, .block > .content)')
161 ops/sec ±1.07%F369 ops/sec ±1.11%720 ops/sec ±1.43%patched-jsdom is the fastest. patched-jsdom is 4.5 times faster than jsdom.
nested and chained :not() selector:
querySelectorAll('p:not(:is(:not(.content))):not(.foo)')
F296 ops/sec ±46.31%998 ops/sec ±0.79%1,168 ops/sec ±1.12%patched-jsdom is the fastest.

Acknowledgments

The following resources have been of great help in the development of the DOM Selector.


Copyright (c) 2023 asamuzaK (Kazz)

FAQs

Package last updated on 01 Feb 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc