selectricity

A concise and effective replacement for jQuery.

selectricity is a simple library used to emulate some of the functonality provided by jQuery without the hefty filesize and unneeded complexity. It is a great tool for dev teams that have junior developers who may be transitioning to using vanilla JS, but can be useful for developers of any skill level. Type definitions now included for TypeScript projects!

Some of the main features of selectricity include:

  • Easy event listening
  • Reduce excessive looping
  • More concise and readable syntax than Vanilla JS

How to import:

 import select from 'selectricity';

Easy event listening

selectricity:

  select('[data-foo]').listen('click', () => {
    console.log('bar');
  });

Compare to Vanilla JS:

  const elements = document.querySelectorAll('[data-foo]');
  
  elements.forEach(($elem) => {
    $elem.addEventListener('click', () => {
      console.log('bar');
    });
  });

You can pass multiple event names to the "listen" method as you can in jQuery:

selectricity:

  const hoverElements = select('[data-hotspot]');

  hoverElements.listen('mouseenter mouseleave', ({ $node }) => {
    $node.toggleClass('active');
  });

Compare to Vanilla JS:

  const hoverElements = document.querySelectorAll('[data-hotspot]');

  hoverElements.forEach((el) => {
    el.addEventListener('mouseenter', () => {
      el.classList.toggle('active');
    });
    el.addEventListener('mouseleave', () => {
      el.classList.toggle('active');
    });
  })

Use object destructuring within the listen callback function to leverage helpful data. The data returned from the listen method are:

  • $node (the current node the event was fired on)
  • e (the event)
  • index (the index of the node in the query)
  const buttons = select('[data-button]');
  
  buttons.listen('click', ({ $node, e, index }) => {
    // callback code here
  });

To add an event listener to a dynamic element, simply pass a value of true as the second argument of the listen method.

  const buttons = select('[data-button]');
  
  buttons.listen('click', ({ $node, e, index }) => {
    // callback code here
  }, true);

Reduce excessive looping

In the following example, we will update the active image based on the index of the currently selected button.

selectricity:

  const buttons = select('[data-button]');
  const images = select('[data-image]');
  
  buttons.listen('click', ({ $node, e, index }) => {
    e.preventDefault();
    // remove active class from all buttons without looping!
    buttons.removeClass('active');
    // add active class to currently clicked button
    $node.addClass('active');
    // remove active class from all images without looping!
    images.removeClass('active');
    // add active class to image with the same index as the currently clicked button
    images[index].addClass('active');
  });

Compare to Vanilla JS:

  const buttons = document.querySelectorAll('[data-button]');
  const images = document.querySelectorAll('[data-image]');

  buttons.forEach((button, index) => {
    button.addEventListener('click', (e) => {
      e.preventDefault();
      // notice here how loops also create problematic variable shadowing which require awkward variable names in the loop to avoid duplication of variable names in parent scopes.
      buttons.forEach((btn) => {
        btn.classList.remove('active');
      });
      images.forEach((image) => {
        image.classList.remove('active');
      });

      button.classList.add('active');
      images[index].classList.add('active');
    });
  });

By using select JS in this instance, we've reduced our code from 16 lines to 10, completely removed the presence of looping, and made the code much easier to scan.

By default, select will search for the selector at the document level, but a different parent in which to perform the query can be provided as the second argument to the function. This can be especially useful when using web components:

JS:

  // update corresponing variant id on "Add to Cart" button as user selects different swatches.
  class AddToCart extends HTMLElement {
    constructor() {
      super();
      
      this.swatches = select('[data-swatch]', this);
      this.addToCart = select('[data-add-to-cart]', this);

      this.swatches.listen('click', ({ $node }) => {
        const { variantId } = $node.dataset;
        // remove active class from all swatches without looping!
        this.swatches.removeClass('swatch--selected');
        // add class to currently clicked node
        $node.addClass('swatch--selected');
        // update variant id value on add to cart button
        this.addToCart.dataset.addToCart = variantId;
      });
    }
  }

HTML:

  <add-to-cart>
    <button class="btn btn--primary" data-add-to-cart="12345">
      Add To Cart
    </button>
    <ul class="swatch-list">
      <li>
        <button class="swatch swatch--selected" data-swatch data-variant-id="12345">
          Grey
        </button>
      </li>
      <li>
        <button class="swatch" data-swatch data-variant-id="23456">
          Green
        </button>
      </li>
      <li>
        <button class="swatch" data-swatch data-variant-id="34567">
          Brown
        </button>
      </li>
    </ul>
  </add-to-cart>

API

Methods

listen(eventName, callback, dynamic) ⇒ void

Attach event listeners to selected element(s).

Param Type Description
eventName string Name of event to listen for on selected element(s). For multiple events, separate each event name by a single space.
callback function Callback function to fire on event.
dynamic boolean Indicates if element was dynamically generated.

addClass(className) ⇒ void

Add class to selected element(s).

Param Type Description
className string Name of the class to add.

removeClass(className) ⇒ void

Remove class from selected element(s).

Param Type Description
className string name of the class to remove.

toggleClass(className) ⇒ void

Toggle class on selected element(s).

Param Type Description
className string name of the class to toggle.

addAttr(attribute, value) ⇒ void

Add attribute to selected element(s).

Param Type Description
attribute string name of the attribute to add.
value string value of the attribute to add. Defaults to empty string.

removeAttr(attribute) ⇒ void

Remove attribute from selected element(s).

Param Type Description
attribute string name of the attribute to remove.

toggleAttr(attribute) ⇒ void

Toggle attribute on selected element(s).

Param Type Description
attribute string name of the attribute to toggle.
value string value of the attribute to toggle. Defaults to empty string.