JetEngine Listing Grid — Skeleton Loading

This guide explains how to enable skeleton loading for JetEngine Listing Grids, which widgets Auto Apply recognizes, how to add manual classes, and how to extend compatibility without changing this plugin.

How To Start

Overview

Supported Widgets (Auto Apply recognition)

Elementor (Default):

JetEngine:

JetElements:

Dynamic Elementor Extension:

Notes:


Special Skeleton Classes

Optional helpers

Absolute positioning tip:

selector {
  --hw-skeleton-original-position: absolute;
}

Keeps the element from snapping if it was absolutely positioned. Change the selector to your widget class name

Listing Grid Controls

After enabling “Skeleton Loading” you can set:

Auto Apply — How it Works

Manual Usage — Quick Examples

Important: For any other widget not listed above, you can always add the universal skeleton-loading class. This applies the loading effect to the widget wrapper as a whole (a single block skeleton) and works universally — there is no widget that “cannot” receive a skeleton. Use this when no specialized class is needed.

Notes & Tips

Per‑Widget Auto Apply Opt‑out

If you need to exclude a specific widget from Auto Apply inside a Listing Grid, open the widget in Elementor → Advanced tab → Attributes and add:

Key: data-hw-skeleton-auto Value: no

Copy paste: data-hw-skeleton-auto|no

This prevents the JS auto‑detection from assigning skeleton classes to that widget while the grid is loading. Manual classes still work as usual.

Extending Without Modifying This Plugin

You can add compatibility for your own widgets without changing this codebase.

  1. Manual (no code)
  1. Front‑end shim (theme/companion plugin)
(function ($) {
  var MAP = {
    "acme-card.default": {
      classes: ["skeleton-loading"],
      shapes: {
        ".acme-card__image": "hw-skel-block",
        ".acme-card__title": "hw-skel-block",
        ".acme-card__desc": "hw-skel-block",
      },
    },
  };

  function inLoadingState($grid) {
    return (
      $grid &&
      $grid.length &&
      ($grid.hasClass("jet-listing-grid-loading") ||
        $grid.hasClass("hw-js-skeleton-loading"))
    );
  }

  function getProviderGrids(provider, queryId) {
    var $result = $();
    if (queryId) {
      var selectors = [
        '.jet-listing-grid[data-hw-query-id="' + queryId + '"]',
        ".jet-listing-grid-" + queryId,
        '.jet-listing-grid[data-query-id="' + queryId + '"]',
      ];
      $result = $(selectors.join(", ")).filter(".jet-listing-grid");
      if (!$result.length) {
        var $items = $(
          '.jet-listing-grid__items[data-hw-query-id="' +
            queryId +
            '"], .jet-listing-grid__items[data-query-id="' +
            queryId +
            '"]'
        );
        if ($items.length) $result = $items.closest(".jet-listing-grid");
      }
    }
    if (!$result.length && provider) {
      var candidate =
        provider.$provider ||
        provider.container ||
        provider.$container ||
        provider;
      var $c = candidate ? $(candidate) : $();
      if ($c.length)
        $result = $c.is(".jet-listing-grid")
          ? $c
          : $c.closest(".jet-listing-grid");
    }
    return $result;
  }

  function applyCompat(root) {
    var $roots = $(root || document);
    var $grids = $roots.filter(".jet-listing-grid");
    if (!$grids.length) $grids = $roots.find(".jet-listing-grid");
    if (!$grids.length) return;

    $grids.each(function () {
      var $grid = $(this);
      if (!inLoadingState($grid)) return;
      Object.keys(MAP).forEach(function (type) {
        var cfg = MAP[type];
        $grid.find('[data-widget_type="' + type + '"]').each(function () {
          var $w = $(this);
          (cfg.classes || []).forEach(function (cls) {
            if (cls && !$w.hasClass(cls)) $w.addClass(cls);
          });
          if (cfg.shapes) {
            Object.keys(cfg.shapes).forEach(function (sel) {
              $w.find(sel).addClass(cfg.shapes[sel]);
            });
          }
        });
      });
    });
  }

  $(function () {
    applyCompat($(".jet-listing-grid"));
  });
  $(document).on(
    "jet-engine/listing/ajax-get-listing/done",
    function (_e, $html) {
      var $scope = $html && $html.length ? $html : $(document);
      var $grid = $scope.closest(".jet-listing-grid");
      applyCompat($grid.length ? $grid : $scope);
    }
  );
  $(document).on(
    "jet-engine/listing-grid/after-load-more",
    function (_e, inst) {
      var $scope = inst && inst.container ? $(inst.container) : $(document);
      applyCompat($scope);
    }
  );

  var bus =
    (window.JetSmartFilters &&
      (window.JetSmartFilters.events ||
        window.JetSmartFilters.eventBus ||
        window.JetSmartFilters.bus)) ||
    null;
  if (bus && typeof bus.subscribe === "function") {
    try {
      bus.subscribe("ajaxFilters/start-loading", function (provider, queryId) {
        var $grids = getProviderGrids(provider, queryId);
        applyCompat($grids.length ? $grids : $(".jet-listing-grid"));
      });
      bus.subscribe("ajaxFilters/end-loading", function (provider, queryId) {
        var $grids = getProviderGrids(provider, queryId);
        applyCompat($grids.length ? $grids : $(".jet-listing-grid"));
      });
    } catch (e) {}
  }
})(jQuery);

Notes:

  1. Server‑side (template)