A modern, context-aware, and extendable CSS selector engine built on top of querySelectorAll
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
Go to file
Ryan Morr 38ee270863
Build v1.0.1
5 years ago
dist Build v1.0.1 5 years ago
src Refactor query and filter functions 5 years ago
test Add test case for case-insensitive attribute selector 5 years ago
.babelrc Update dependencies 5 years ago
.editorconfig Initial commit 8 years ago
.eslintrc Update dependencies 5 years ago
.gitattributes Update dependencies 5 years ago
.gitignore Initial commit 8 years ago
.travis.yml Update dependencies 5 years ago
README.md Update documentation 5 years ago
UNLICENSE Initial commit 8 years ago
gulpfile.babel.js Update dependencies 5 years ago
package-lock.json Remove internal parsers in favor of @ryanmorr/css-selector-parser 5 years ago
package.json Bump version 5 years ago

README.md

sonic

Version Badge Build Status License

A modern, context-aware, and extendable CSS selector engine built on top of querySelectorAll.

Install

Download the development or minified version, or install via NPM:

npm install @ryanmorr/sonic

Usage

Find a single element:

import { find } from '@ryanmorr/sonic';

// Returns the matching element or null if no match is found
const el = find('#container');

Query for multiple elements:

import { query } from '@ryanmorr/sonic';

// Returns an array of all matching elements
const elements = query('.items');

Check if an element matches a selector string:

import { is } from '@ryanmorr/sonic';

const isMatch = is(element, 'div.class[attr=value]');

Provide an element or selector string as an optional second argument as the root of the query:

const el = find('[attr]', element);
const elements = query(':first-child', '#header');

Use leading combinators:

const divs = query('> div');
const blocks = query('+ .block');
const checked = query('~ :checked');

Extendable

Create custom pseudo-class selectors (must return a boolean):

import { find, query, pseudos } from '@ryanmorr/sonic';

pseudos.foo = (el) => {
    return el.hasAttribute('foo');
};

pseudos.bar = (el, value) => {
    return el.hasAttribute(value);
};

const el = find(':foo');
const elements = query(':bar(class)');

Context-Aware

Sonic addresses the long-standing flaw in querySelector and querySelectorAll that sees element-rooted queries search relative to the document and not the element itself:

<section id="container">
    <em>Level 1</em>
    <section>
        <em>Level 2</em>
    </section>
</section>
// Expected <em>Level 2</em>, but returns <em>Level 1</em>, doh!
document.querySelector('#container').querySelector('section em');

Apparently, this behavior is purported to be correct given how long it has endured. Sonic, on the other hand, abides by the principle of least surprise and gives you exactly what you expect.

// Returns <em>Level 2</em> as expected, hooray!
const elements = query('section em', '#container');

License

This project is dedicated to the public domain as described by the Unlicense.