How to Use jQuery cssHooks for Custom CSS Properties

jQuery's $.cssHooks object allows developers to extend the native .css() method by defining custom property handlers to normalize browser discrepancies, manage vendor prefixes, or create virtual CSS properties. This guide outlines how to define custom getters and setters using $.cssHooks, inspects their underlying syntax, and provides a functional implementation example.

Understanding the $.cssHooks Object

The $.cssHooks object directly exposes jQuery's internal mechanism for getting and setting CSS values. When a property is registered in $.cssHooks, any subsequent call to $(element).css("propertyName") or $(element).css("propertyName", "value") routes through the custom handler rather than the standard browser style property.

A custom hook consists of an object assigned to a specific camelCase property name within $.cssHooks, containing a get function, a set function, or both.

$.cssHooks["customPropertyName"] = {
  get: function(elem, computed, extra) {
    // Logic for retrieving the property value
    return value;
  },
  set: function(elem, value) {
    // Logic for applying the property value
    elem.style["styleName"] = value;
  }
};

Handler Parameters

  • get(elem, computed, extra):

    • elem: The DOM element being inspected.
    • computed: A boolean indicating whether computed styles are requested (via window.getComputedStyle).
    • extra: Optional extra data passed internally by certain jQuery layout methods.
    • Return Value: Must return a string or number representing the retrieved value.
  • set(elem, value):

    • elem: The DOM element being updated.
    • value: The incoming value passed to the .css() setter.
    • Return Value: Does not require a return value, but may return an empty string to avoid setting standard styles.

Defining a Custom CSS Property Handler

A common application of $.cssHooks is creating abstraction layers or compound property shortcuts. The following example creates a custom property called quickGlow that reads and writes a specific CSS boxShadow format.

(function($) {
  // Define the custom hook for "quickGlow"
  $.cssHooks.quickGlow = {
    get: function(elem, computed, extra) {
      // Return the current box-shadow value
      return $.css(elem, "boxShadow");
    },
    set: function(elem, value) {
      // If a color is provided, format it into a glowing box-shadow
      if (value) {
        elem.style.boxShadow = "0 0 15px " + value;
      } else {
        elem.style.boxShadow = "none";
      }
    }
  };
})(jQuery);

Using the Custom Hook

Once defined, the custom hook integrates transparently with standard jQuery syntax:

// Setting the custom CSS property
$("#targetElement").css("quickGlow", "rgba(0, 150, 255, 0.8)");

// Reading the custom CSS property
var currentGlow = $("#targetElement").css("quickGlow");
console.log(currentGlow); // Outputs: "rgb(0, 150, 255) 0px 0px 15px 0px"

Creating Vendor-Prefix Normalization

$.cssHooks is also commonly used to support older browser features that require vendor prefixes by checking support before applying hooks:

(function($) {
  var style = document.documentElement.style;
  var prefixes = ["Webkit", "Moz", "ms", "O"];
  
  function getSupportedPropertyName(prop) {
    if (prop in style) return prop;
    var capitalized = prop.charAt(0).toUpperCase() + prop.slice(1);
    for (var i = 0; i < prefixes.length; i++) {
      var vendorProp = prefixes[i] + capitalized;
      if (vendorProp in style) return vendorProp;
    }
    return null;
  }

  var userSelectProp = getSupportedPropertyName("userSelect");

  // Only assign hook if a prefix is required
  if (userSelectProp && userSelectProp !== "userSelect") {
    $.cssHooks.userSelect = {
      get: function(elem, computed, extra) {
        return $.css(elem, userSelectProp);
      },
      set: function(elem, value) {
        elem.style[userSelectProp] = value;
      }
    };
  }
})(jQuery);

After registering this hook, calling $(elem).css("userSelect", "none") automatically targets the vendor-prefixed version supported by the client browser without additional conditional logic in application code.