How to Trigger Custom Functions on Shopify Variant Selection Without Override

How to Trigger Custom Functions on Shopify Variant Selection Without Override

When building custom functionality that needs to respond to variant changes in Shopify themes, you often need a way to hook into variant selection events without breaking the theme’s existing functionality. Here are three reliable methods that work across different theme architectures:

Method 1: Modern Theme Events (Recommended for newer themes)

Many modern themes like Loft use custom event systems. Check if your theme dispatches variant change events:

jQuery('#shopify-section-product-template').on('theme:variants:changed', function(evt, variantObj){
   console.log('Variant changed to: ' + variantObj.sku);
   console.log(variantObj);
   
   // Your custom functionality here
   myCustomVariantHandler(variantObj);
});

Method 2: Legacy OptionSelectors Override

For themes using the older Shopify.OptionSelectors, you can extend the global selectCallback function:

(function(){
   var original_selectCallback = window.selectCallback;
   
   window.selectCallback = function(variant, selector) {
      // Always call the original function first
      original_selectCallback(variant, selector);
      
      // Then add your custom functionality
      if (variant) {
         myCustomVariantHandler(variant);
      }
   };
})();

Method 3: History State Tracking (Modern themes with enableHistoryState)

For modern themes that use enableHistoryState: true with OptionSelectors, you can track URL changes:

document.addEventListener('DOMContentLoaded', function(){
   
   function usePushState(handler){
      // Track history state changes without overriding
      function track(fn, handler, before) {
         return function interceptor() {
            if (before) {
               handler.apply(this, arguments);
               return fn.apply(this, arguments);
            } else {
               var result = fn.apply(this, arguments);
               handler.apply(this, arguments);
               return result;
            }
         };
      }

      var currentVariantId = null;
      
      function variantHandler() {
         var selectedVariantId = window.location.search.replace(/.*variant=(\d+).*/, '$1');
         console.log('Checking variant change to: ' + selectedVariantId);
         
         if (!selectedVariantId || selectedVariantId === currentVariantId) return;
         
         currentVariantId = selectedVariantId;
         handler(selectedVariantId);
      }

      // Intercept history methods
      window.history.pushState = track(history.pushState, variantHandler);
      window.history.replaceState = track(history.replaceState, variantHandler);
      window.addEventListener('popstate', variantHandler);
   }
   
   // Initialize with your custom handler
   usePushState(function(variantId) {
      console.log('Variant changed to ID: ' + variantId);
      // Your custom functionality here
      myCustomVariantHandler(variantId);
   });
});

Implementation Tips

  1. Test your theme first - Check browser console for existing events before implementing
  2. Non-destructive approach - These methods preserve existing theme functionality
  3. Fallback strategy - You can combine methods for maximum compatibility
  4. Custom handler function - Replace myCustomVariantHandler() with your actual functionality

Example Custom Handler

function myCustomVariantHandler(variant) {
   // Example: Update custom elements, trigger analytics, etc.
   console.log('Custom variant handler triggered', variant);
   
   // Your specific functionality here
   if (variant && variant.available) {
      // Handle available variant
   } else {
      // Handle unavailable variant
   }
}

Has anyone found other reliable methods for variant change detection? What’s worked best in your experience?

1 Like

Thanks for sharing these methods Aswin!

1 Like