How to Create Custom jQuery Pseudo-Selectors

jQuery allows developers to extend its selector engine using the $.expr[':'] object to build custom pseudo-selectors. This article explains how to define, configure, and execute custom pseudo-selectors to streamline DOM traversal and eliminate repetitive filtering code in your projects.

Understanding $.expr[':']

Under the hood, jQuery uses the Sizzle selector engine. The $.expr[':'] object (an alias for jQuery.expr.pseudos) stores all pseudo-selectors such as :visible, :first, and :checked. By adding a new function to this object, you define a custom filter that jQuery applies to DOM elements during a query.

The callback function assigned to a custom pseudo-selector receives four arguments:

  1. elem: The current raw DOM element being evaluated.
  2. index: The zero-based index of the element in the current collection.
  3. match: An array containing parsing metadata about the selector. match[3] contains any parameter passed inside the parentheses of the selector.
  4. stack: The complete array of elements being filtered.

The function must return true to keep the element in the matched set, or false to exclude it.


Creating a Basic Custom Pseudo-Selector

A basic pseudo-selector evaluates an element's property without taking any arguments.

The following example creates a :blank-input selector that matches input fields that are empty or contain only whitespace:

$.expr[':']['blank-input'] = function(elem) {
  // Ensure the element is an input or textarea
  if (elem.tagName === 'INPUT' || elem.tagName === 'TEXTAREA') {
    return $(elem).val().trim() === '';
  }
  return false;
};

// Usage:
$('input:blank-input').addClass('error-highlight');

Creating a Parameterized Pseudo-Selector

Custom selectors can also accept arguments passed within parentheses (e.g., :min-height(200)). To capture the parameter, read match[3].

The following example creates a :min-width selector to filter elements whose rendered width meets or exceeds a specified pixel value:

$.expr[':']['min-width'] = function(elem, index, match) {
  // Parse the argument passed inside the parentheses: :min-width(value)
  var minWidth = parseInt(match[3], 10);

  if (isNaN(minWidth)) {
    return false;
  }

  return $(elem).width() >= minWidth;
};

// Usage:
$('div:min-width(500)').css('border', '2px solid green');

Best Practices

  • Native JavaScript over jQuery Wrapping: Inside the selector function, inspect elem using native JavaScript properties (e.g., elem.getAttribute(), elem.offsetWidth) whenever possible. Avoiding $(elem) calls inside the function significantly improves selector performance across large DOM trees.
  • Compatibility: In modern jQuery (v1.8 and newer), $.expr[':'] is officially an alias for $.expr.pseudos. While $.expr[':'] remains fully supported for backward compatibility, you can use $.expr.pseudos interchangeably using the same syntax.