{"id":13716889,"url":"https://github.com/syntax-tree/hast-util-select","last_synced_at":"2025-07-12T07:37:59.845Z","repository":{"id":57261707,"uuid":"87732510","full_name":"syntax-tree/hast-util-select","owner":"syntax-tree","description":"utility to add `querySelector`, `querySelectorAll`, and `matches` support for hast","archived":false,"fork":false,"pushed_at":"2025-02-19T14:34:38.000Z","size":269,"stargazers_count":41,"open_issues_count":0,"forks_count":1,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-03-20T21:11:33.056Z","etag":null,"topics":["hast","hast-util","html","matches","queryselector","select","selectall","util"],"latest_commit_sha":null,"homepage":"https://unifiedjs.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/syntax-tree.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"unifiedjs","open_collective":"unified"}},"created_at":"2017-04-09T19:07:55.000Z","updated_at":"2025-03-15T10:43:33.000Z","dependencies_parsed_at":"2024-06-18T15:37:09.562Z","dependency_job_id":"720a4345-2243-4ee0-ab76-9257618a1deb","html_url":"https://github.com/syntax-tree/hast-util-select","commit_stats":{"total_commits":135,"total_committers":1,"mean_commits":135.0,"dds":0.0,"last_synced_commit":"ffaebb2879cdfbbe1938cf706310e7cef5d7e6a7"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syntax-tree%2Fhast-util-select","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syntax-tree%2Fhast-util-select/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syntax-tree%2Fhast-util-select/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/syntax-tree%2Fhast-util-select/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/syntax-tree","download_url":"https://codeload.github.com/syntax-tree/hast-util-select/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252405835,"owners_count":21742681,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hast","hast-util","html","matches","queryselector","select","selectall","util"],"created_at":"2024-08-03T00:01:15.390Z","updated_at":"2025-05-07T06:31:43.933Z","avatar_url":"https://github.com/syntax-tree.png","language":"JavaScript","readme":"# hast-util-select\n\n[![Build][badge-build-image]][badge-build-url]\n[![Coverage][badge-coverage-image]][badge-coverage-url]\n[![Downloads][badge-downloads-image]][badge-downloads-url]\n[![Size][badge-size-image]][badge-size-url]\n\n[hast][github-hast] utility with equivalents for\n`matches`, `querySelector`, and `querySelectorAll`.\n\n## Contents\n\n* [What is this?](#what-is-this)\n* [When should I use this?](#when-should-i-use-this)\n* [Install](#install)\n* [Use](#use)\n* [API](#api)\n  * [`matches(selector, node[, space])`](#matchesselector-node-space)\n  * [`select(selector, tree[, space])`](#selectselector-tree-space)\n  * [`selectAll(selector, tree[, space])`](#selectallselector-tree-space)\n  * [`Space`](#space)\n* [Support](#support)\n* [Unsupported](#unsupported)\n* [Types](#types)\n* [Compatibility](#compatibility)\n* [Security](#security)\n* [Related](#related)\n* [Contribute](#contribute)\n* [License](#license)\n\n## What is this?\n\nThis package lets you find nodes in a tree,\nsimilar to how `matches`,\n`querySelector`,\nand\n`querySelectorAll` work with the DOM.\n\nOne notable difference between DOM and hast is that DOM nodes have references\nto their parents,\nmeaning that `document.body.matches(':last-child')` can be evaluated to check\nwhether the body is the last child of its parent.\nThis information is not stored in hast,\nso selectors like that don’t work.\n\n## When should I use this?\n\nThis is a small utility that is quite useful,\nbut is rather slow if you use it a lot.\nFor each call,\nit has to walk the entire tree.\nIn some cases,\nwalking the tree once with\n[`unist-util-visit`][github-unist-util-visit]\nis smarter,\nsuch as when you want to change certain nodes.\nOn the other hand,\nthis is quite powerful and fast enough for many other cases.\n\nThis utility is similar to\n[`unist-util-select`][github-unist-util-select],\nwhich can find and match any unist node.\n\n## Install\n\nThis package is [ESM only][github-gist-esm].\nIn Node.js (version 16+),\ninstall with [npm][npmjs-install]:\n\n```sh\nnpm install hast-util-select\n```\n\nIn Deno with [`esm.sh`][esmsh]:\n\n```js\nimport {matches, select, selectAll} from 'https://esm.sh/hast-util-select@6'\n```\n\nIn browsers with [`esm.sh`][esmsh]:\n\n```html\n\u003cscript type=\"module\"\u003e\n  import {matches, select, selectAll} from 'https://esm.sh/hast-util-select@6?bundle'\n\u003c/script\u003e\n```\n\n## Use\n\n```js\nimport {h} from 'hastscript'\nimport {matches, select, selectAll} from 'hast-util-select'\n\nconst tree = h('section', [\n  h('p', 'Alpha'),\n  h('p', 'Bravo'),\n  h('h1', 'Charlie'),\n  h('p', 'Delta'),\n  h('p', 'Echo'),\n  h('p', 'Foxtrot'),\n  h('p', 'Golf')\n])\n\nconsole.log(matches('section', tree)) // `true`\n\nconsole.log(select('h1 ~ :nth-child(even)', tree))\n// The paragraph with `Delta`\n\nconsole.log(selectAll('h1 ~ :nth-child(even)', tree))\n// The paragraphs with `Delta` and `Foxtrot`\n```\n\n## API\n\nThis package exports the identifiers [`matches`][api-matches],\n[`select`][api-select],\nand [`selectAll`][api-select-all].\nThere is no default export.\n\n### `matches(selector, node[, space])`\n\nCheck that the given `node` matches `selector`.\n\nThis only checks the element itself,\nnot the surrounding tree.\nThus,\nnesting in selectors is not supported (`p b`, `p \u003e b`),\nneither are selectors like `:first-child`,\netc.\nThis only checks that the given element matches the selector.\n\n###### Parameters\n\n* `selector`\n  (`string`, example: `'h1'`, `'a, b'`)\n  — CSS selector\n* `node`\n  ([`Node`][github-hast-nodes], optional)\n  — node that might match `selector`,\n  should be an element\n* `space`\n  ([`Space`][api-space], default: `'html'`)\n  — name of namespace\n\n###### Returns\n\nWhether `node` matches `selector` (`boolean`).\n\n###### Example\n\n```js\nimport {h} from 'hastscript'\nimport {matches} from 'hast-util-select'\n\nmatches('b, i', h('b')) // =\u003e true\nmatches(':any-link', h('a')) // =\u003e false\nmatches(':any-link', h('a', {href: '#'})) // =\u003e true\nmatches('.classy', h('a', {className: ['classy']})) // =\u003e true\nmatches('#id', h('a', {id: 'id'})) // =\u003e true\nmatches('[lang|=en]', h('a', {lang: 'en'})) // =\u003e true\nmatches('[lang|=en]', h('a', {lang: 'en-GB'})) // =\u003e true\n```\n\n### `select(selector, tree[, space])`\n\nSelect the first element that matches `selector` in the given `tree`.\nSearches the tree in *[preorder][github-unist-preorder]*.\n\n###### Parameters\n\n* `selector`\n  (`string`, example: `'h1'`, `'a, b'`)\n  — CSS selector, such as (`h1`, `a, b`)\n* `tree`\n  ([`Node`][github-hast-nodes], optional)\n  — tree to search\n* `space`\n  ([`Space`][api-space], default: `'html'`)\n  — name of namespace\n\n###### Returns\n\nFirst element in `tree` that matches `selector` or `undefined` if nothing is\nfound.\nThis could be `tree` itself.\n\n###### Example\n\n```js\nimport {h} from 'hastscript'\nimport {select} from 'hast-util-select'\n\nconsole.log(\n  select(\n    'h1 ~ :nth-child(even)',\n    h('section', [\n      h('p', 'Alpha'),\n      h('p', 'Bravo'),\n      h('h1', 'Charlie'),\n      h('p', 'Delta'),\n      h('p', 'Echo')\n    ])\n  )\n)\n```\n\nYields:\n\n```js\n{ type: 'element',\n  tagName: 'p',\n  properties: {},\n  children: [ { type: 'text', value: 'Delta' } ] }\n```\n\n### `selectAll(selector, tree[, space])`\n\nSelect all elements that match `selector` in the given `tree`.\nSearches the tree in *[preorder][github-unist-preorder]*.\n\n###### Parameters\n\n* `selector`\n  (`string`, example: `'h1'`, `'a, b'`)\n  — CSS selector\n* `tree`\n  ([`Node`][github-hast-nodes], optional)\n  — tree to search\n* `space`\n  ([`Space`][api-space], default: `'html'`)\n  — name of namespace\n\n###### Returns\n\nElements in `tree` that match `selector`.\nThis could include `tree` itself.\n\n###### Example\n\n```js\nimport {h} from 'hastscript'\nimport {selectAll} from 'hast-util-select'\n\nconsole.log(\n  selectAll(\n    'h1 ~ :nth-child(even)',\n    h('section', [\n      h('p', 'Alpha'),\n      h('p', 'Bravo'),\n      h('h1', 'Charlie'),\n      h('p', 'Delta'),\n      h('p', 'Echo'),\n      h('p', 'Foxtrot'),\n      h('p', 'Golf')\n    ])\n  )\n)\n```\n\nYields:\n\n```js\n[ { type: 'element',\n    tagName: 'p',\n    properties: {},\n    children: [ { type: 'text', value: 'Delta' } ] },\n  { type: 'element',\n    tagName: 'p',\n    properties: {},\n    children: [ { type: 'text', value: 'Foxtrot' } ] } ]\n```\n\n### `Space`\n\nNamespace (TypeScript type).\n\n###### Type\n\n```ts\ntype Space = 'html' | 'svg'\n```\n\n## Support\n\n* [x] `*` (universal selector)\n* [x] `,` (multiple selector)\n* [x] `p` (type selector)\n* [x] `.class` (class selector)\n* [x] `#id` (id selector)\n* [x] `article p` (combinator: descendant selector)\n* [x] `article \u003e p` (combinator: child selector)\n* [x] `h1 + p` (combinator: next-sibling selector)\n* [x] `h1 ~ p` (combinator: subsequent sibling selector)\n* [x] `[attr]` (attribute existence)\n* [x] `[attr… i]` (attribute case-insensitive)\n* [x] `[attr… s]` (attribute case-sensitive) (useless, default)\n* [x] `[attr=value]` (attribute equality)\n* [x] `[attr~=value]` (attribute contains in space-separated list)\n* [x] `[attr|=value]` (attribute equality or prefix)\n* [x] `[attr^=value]` (attribute begins with)\n* [x] `[attr$=value]` (attribute ends with)\n* [x] `[attr*=value]` (attribute contains)\n* [x] `:dir()` (functional pseudo-class)\n* [x] `:has()` (functional pseudo-class; also supports `a:has(\u003e b)`)\n* [x] `:is()` (functional pseudo-class)\n* [x] `:lang()` (functional pseudo-class)\n* [x] `:not()` (functional pseudo-class)\n* [x] `:any-link` (pseudo-class)\n* [x] `:blank` (pseudo-class)\n* [x] `:checked` (pseudo-class)\n* [x] `:disabled` (pseudo-class)\n* [x] `:empty` (pseudo-class)\n* [x] `:enabled` (pseudo-class)\n* [x] `:optional` (pseudo-class)\n* [x] `:read-only` (pseudo-class)\n* [x] `:read-write` (pseudo-class)\n* [x] `:required` (pseudo-class)\n* [x] `:root` (pseudo-class)\n* [x] `:scope` (pseudo-class):\n* [x] \\* `:first-child` (pseudo-class)\n* [x] \\* `:first-of-type` (pseudo-class)\n* [x] \\* `:last-child` (pseudo-class)\n* [x] \\* `:last-of-type` (pseudo-class)\n* [x] \\* `:only-child` (pseudo-class)\n* [x] \\* `:only-of-type` (pseudo-class)\n* [x] \\* `:nth-child()` (functional pseudo-class)\n* [x] \\* `:nth-last-child()` (functional pseudo-class)\n* [x] \\* `:nth-last-of-type()` (functional pseudo-class)\n* [x] \\* `:nth-of-type()` (functional pseudo-class)\n\n## Unsupported\n\n* [ ] † `||` (column combinator)\n* [ ] † `ns|E` (namespace type selector)\n* [ ] † `*|E` (any namespace type selector)\n* [ ] † `|E` (no namespace type selector)\n* [ ] † `[ns|attr]` (namespace attribute)\n* [ ] † `[*|attr]` (any namespace attribute)\n* [ ] † `[|attr]` (no namespace attribute)\n* [ ] ‖ `:nth-child(n of S)` (functional pseudo-class, note: scoping to\n  parents is not supported)\n* [ ] ‖ `:nth-last-child(n of S)` (functional pseudo-class, note: scoping to\n  parents is not supported)\n* [ ] † `:active` (pseudo-class)\n* [ ] † `:autofill` (pseudo-class)\n* [ ] † `:buffering` (pseudo-class)\n* [ ] § `:closed` (pseudo-class)\n* [ ] † `:current` (pseudo-class)\n* [ ] † `:current()` (functional pseudo-class)\n* [ ] † `:default` (pseudo-class)\n* [ ] † `:defined` (pseudo-class)\n* [ ] † `:focus` (pseudo-class)\n* [ ] † `:focus-visible` (pseudo-class)\n* [ ] † `:focus-within` (pseudo-class)\n* [ ] † `:fullscreen` (pseudo-class)\n* [ ] † `:future` (pseudo-class)\n* [ ] § `:host()` (functional pseudo-class)\n* [ ] § `:host-context()` (functional pseudo-class)\n* [ ] † `:hover` (pseudo-class)\n* [ ] ‡ `:in-range` (pseudo-class)\n* [ ] † `:indeterminate` (pseudo-class)\n* [ ] ‡ `:invalid` (pseudo-class)\n* [ ] † `:link` (pseudo-class)\n* [ ] † `:local-link` (pseudo-class)\n* [ ] † `:modal` (pseudo-class)\n* [ ] † `:muted` (pseudo-class)\n* [ ] † `:nth-col()` (functional pseudo-class)\n* [ ] † `:nth-last-col()` (functional pseudo-class)\n* [ ] § `:open` (pseudo-class)\n* [ ] ‡ `:out-of-range` (pseudo-class)\n* [ ] † `:past` (pseudo-class)\n* [ ] † `:paused` (pseudo-class)\n* [ ] † `:placeholder-shown` (pseudo-class)\n* [ ] † `:playing` (pseudo-class)\n* [ ] † `:seeking` (pseudo-class)\n* [ ] † `:stalled` (pseudo-class)\n* [ ] † `:target` (pseudo-class)\n* [ ] † `:target-within` (pseudo-class)\n* [ ] † `:user-invalid` (pseudo-class)\n* [ ] ‡ `:valid` (pseudo-class)\n* [ ] † `:visited` (pseudo-class)\n* [ ] † `:volume-locked` (pseudo-class)\n* [ ] § `:where()` (functional pseudo-class)\n* [ ] † `::before` (pseudo-elements: none are supported)\n\n###### Notes\n\n* \\* — not supported in `matches`\n* † — needs a user,\n  browser,\n  interactivity,\n  scripting,\n  or whole CSS to make sense\n* ‡ — not very interested in writing / including the code for this\n* § — too new,\n  the spec is still changing\n* ‖ — pr wanted!\n* `:any()` and `:matches()` are renamed to `:is()` in CSS.\n\n## Types\n\nThis package is fully typed with [TypeScript][].\nIt exports the additional type [`Space`][api-space].\n\n## Compatibility\n\nProjects maintained by the unified collective are compatible with maintained\nversions of Node.js.\n\nWhen we cut a new major release,\nwe drop support for unmaintained versions of Node.\nThis means we try to keep the current release line,\n`hast-util-select@6`,\ncompatible with Node.js 16.\n\n## Security\n\nThis package does not change the syntax tree so there are no openings for\n[cross-site scripting (XSS)][wikipedia-xss] attacks.\n\n## Related\n\n* [`unist-util-select`][github-unist-util-select]\n  — select unist nodes with CSS-like selectors\n* [`hast-util-find-and-replace`](https://github.com/syntax-tree/hast-util-find-and-replace)\n  — find and replace text in a hast tree\n* [`hast-util-parse-selector`](https://github.com/syntax-tree/hast-util-parse-selector)\n  — create an element from a simple CSS selector\n* [`hast-util-from-selector`](https://github.com/syntax-tree/hast-util-from-selector)\n  — create an element from a complex CSS selector\n\n## Contribute\n\nSee [`contributing.md`][health-contributing]\nin\n[`syntax-tree/.github`][health]\nfor ways to get started.\nSee [`support.md`][health-support] for ways to get help.\n\nThis project has a [code of conduct][health-coc].\nBy interacting with this repository,\norganization,\nor community you agree to abide by its terms.\n\n## License\n\n[MIT][file-license] © [Titus Wormer][wooorm]\n\n\u003c!-- Definitions --\u003e\n\n[api-matches]: #matchesselector-node-space\n\n[api-select]: #selectselector-tree-space\n\n[api-select-all]: #selectallselector-tree-space\n\n[api-space]: #space\n\n[badge-build-image]: https://github.com/syntax-tree/hast-util-select/workflows/main/badge.svg\n\n[badge-build-url]: https://github.com/syntax-tree/hast-util-select/actions\n\n[badge-coverage-image]: https://img.shields.io/codecov/c/github/syntax-tree/hast-util-select.svg\n\n[badge-coverage-url]: https://codecov.io/github/syntax-tree/hast-util-select\n\n[badge-downloads-image]: https://img.shields.io/npm/dm/hast-util-select.svg\n\n[badge-downloads-url]: https://www.npmjs.com/package/hast-util-select\n\n[badge-size-image]: https://img.shields.io/bundlejs/size/hast-util-select\n\n[badge-size-url]: https://bundlejs.com/?q=hast-util-select\n\n[esmsh]: https://esm.sh\n\n[file-license]: license\n\n[github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c\n\n[github-hast]: https://github.com/syntax-tree/hast\n\n[github-hast-nodes]: https://github.com/syntax-tree/hast#nodes\n\n[github-unist-preorder]: https://github.com/syntax-tree/unist#preorder\n\n[github-unist-util-select]: https://github.com/syntax-tree/unist-util-select\n\n[github-unist-util-visit]: https://github.com/syntax-tree/unist-util-visit\n\n[health]: https://github.com/syntax-tree/.github\n\n[health-coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md\n\n[health-contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md\n\n[health-support]: https://github.com/syntax-tree/.github/blob/main/support.md\n\n[npmjs-install]: https://docs.npmjs.com/cli/install\n\n[typescript]: https://www.typescriptlang.org\n\n[wikipedia-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting\n\n[wooorm]: https://wooorm.com\n","funding_links":["https://github.com/sponsors/unifiedjs","https://opencollective.com/unified"],"categories":["hast utilities"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyntax-tree%2Fhast-util-select","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsyntax-tree%2Fhast-util-select","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsyntax-tree%2Fhast-util-select/lists"}