> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://support.teeinblue.com/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Adding Custom Variants Badge to your Product


Add visual labels to specific variant values (e.g., **Bestsellers**, **Limited Edition**, or **Recommended**) on your product page to help customers identify key options quickly.

![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/bestsellerbadge_1xbgx5a.png)



## Important Notes

* **Backup your theme:** Always create a duplicate of your theme before editing code.
* **Liquid knowledge:** Basic familiarity with Shopify Liquid is required.
* **Support:** Contact the support team if you need assistance with this implementation.


---

# Step 1: Create a Product Metafield

Define where the badge data will be stored in your Shopify admin.
*  Navigate to **Shopify Admin** > **Settings** > **Metafields and metaobjects > Metafields definitions** > **Products**.
*  Click **Add definition**.
*  Set the **Name** to: `Teeinblue Custom Badges`.
*  Set the **Namespace and key** to exactly: `teeinblue.custom_badges`.
*  Select **Type**: `JSON`.
*  Select **One value**.
*  **Save**.
![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/json_wchlcf.jpg)


|| **Note:** The metafield key must be exactly `teeinblue.custom_badges` for the script to function.

| Tips: You can pin this metafield to quickly access it on your Shopify Admin > Product
---

# Step 2: Add Badge Data to Products

Specify which variants get which badges for your chosen products.

*  Go to **Shopify Admin** > **Products** and select a product.
*  Scroll down to the **Metafields** section at the bottom.
*  In the `Teeinblue Custom Badges` field, enter your data in JSON format as below
```
    Key: The exact name of the variant option.
    Value: The text you want displayed on the badge.
```
*  **Save**.

**Example JSON value:**

```
{
  "15oz": "Best Seller"
}
```


![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/monosnap-image-2026-03-20-16-1_1rb0zum.png)

---

# Step 3: Add Liquid Code to the Theme

### 1. Create the Snippet file
*  Go to **Online Store** > **Themes** > **Edit code**.
*  In the left sidebar, locate the **Snippets** folder and click **Add a new snippet**.
*  Name the file: `teeinblue-custom-badges.liquid`.
![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/monosnap-image-2026-03-20-16-2_1nbggjp.png)


*  Paste your snippet code into the file and **Save**.

```
{% if template.name == 'product' %}
  {% assign custom_badges_data = product.metafields.teeinblue.custom_badges.value %}

  <script>
    
    /** 
        1. This variable will define the selectors of the variant picker label
        2. You can add more selector to this variable (from the theme's variant picker
          - for campaign by Shopify products
        3. The below selectors will work for all campaign by Product base
    */
    var VARIANT_LABEL_SELECTORS = ['.tee-radio-label', '.tee-clipart-label'];

    (function () {
      var rawBadgeMap = {{ custom_badges_data | json }};
      var badgeMap = {};
      var BADGE_ATTR = 'data-variant-badge';
      var observer = null;
      var isScheduled = false;

      try {
        badgeMap = typeof rawBadgeMap === 'string'
          ? JSON.parse(rawBadgeMap || '{}')
          : (rawBadgeMap || {});
      } catch (e) {
        badgeMap = {};
      }

      function normalizeText(text) {
        return String(text || '')
          .replace(/\s+/g, ' ')
          .trim()
          .toLowerCase();
      }

      function findBadgeText(labelText) {
        var normalizedLabel = normalizeText(labelText);
        if (!normalizedLabel) return '';

        if (badgeMap[labelText] != null) return String(badgeMap[labelText]);
        if (badgeMap[normalizedLabel] != null) return String(badgeMap[normalizedLabel]);

        var keys = Object.keys(badgeMap);
        for (var i = 0; i < keys.length; i++) {
          if (normalizeText(keys[i]) === normalizedLabel) {
            return String(badgeMap[keys[i]]);
          }
        }

        return '';
      }

      function getLabelText(labelEl) {
        if (!labelEl) return '';

        var clone = labelEl.cloneNode(true);
        var badgeEl = clone.querySelector('[' + BADGE_ATTR + '="1"]');
        if (badgeEl) badgeEl.remove();

        return (clone.textContent || clone.innerText || '')
          .replace(/\s+/g, ' ')
          .trim();
      }

      function getBadgeElement(labelEl) {
        return labelEl.querySelector('[' + BADGE_ATTR + '="1"]');
      }

      function createBadgeElement() {
        var badgeEl = document.createElement('span');
        badgeEl.setAttribute(BADGE_ATTR, '1');
        badgeEl.className = 'variant-badge';
        return badgeEl;
      }

      function updateBadge(labelEl, badgeText) {
        var badgeEl = getBadgeElement(labelEl);

        if (!badgeText) {
          if (badgeEl) {
            badgeEl.remove();
            return true;
          }
          return false;
        }

        if (!badgeEl) {
          badgeEl = createBadgeElement();
          labelEl.appendChild(badgeEl);
        }

        if (badgeEl.textContent !== badgeText) {
          badgeEl.textContent = badgeText;
          return true;
        }

        return !badgeEl.isConnected;
      }

      function getAllLabels() {
        var uniqueLabels = new Map();

        for (var i = 0; i < VARIANT_LABEL_SELECTORS.length; i++) {
          var selector = VARIANT_LABEL_SELECTORS[i];
          var elements = document.querySelectorAll(selector);

          for (var j = 0; j < elements.length; j++) {
            uniqueLabels.set(elements[j], true);
          }
        }

        return Array.from(uniqueLabels.keys());
      }

      function disconnectObserver() {
        if (observer) observer.disconnect();
      }

      function connectObserver() {
        if (!observer) return;

        var root = document.body || document.documentElement;
        if (!root) return;

        observer.observe(root, {
          subtree: true,
          childList: true
        });
      }

      function applyBadges() {
        if (!badgeMap || typeof badgeMap !== 'object') return;

        disconnectObserver();

        var labels = getAllLabels();

        for (var i = 0; i < labels.length; i++) {
          var labelEl = labels[i];
          var labelText = getLabelText(labelEl);
          var badgeText = findBadgeText(labelText);
          updateBadge(labelEl, badgeText);
        }

        connectObserver();
      }

      function isRelevantNode(node) {
        if (!node || node.nodeType !== 1) return false;
        if (node.hasAttribute && node.hasAttribute(BADGE_ATTR)) return false;

        for (var i = 0; i < VARIANT_LABEL_SELECTORS.length; i++) {
          var selector = VARIANT_LABEL_SELECTORS[i];
          if (!selector) continue;

          if (node.matches && node.matches(selector)) return true;
          if (node.querySelector && node.querySelector(selector)) return true;
        }

        return false;
      }

      function queueApply() {
        if (isScheduled) return;

        isScheduled = true;

        requestAnimationFrame(function () {
          isScheduled = false;
          applyBadges();
        });
      }

      function startObserver() {
        observer = new MutationObserver(function (mutations) {
          for (var i = 0; i < mutations.length; i++) {
            var mutation = mutations[i];

            for (var j = 0; j < mutation.addedNodes.length; j++) {
              if (isRelevantNode(mutation.addedNodes[j])) {
                queueApply();
                return;
              }
            }

            for (var k = 0; k < mutation.removedNodes.length; k++) {
              if (isRelevantNode(mutation.removedNodes[k])) {
                queueApply();
                return;
              }
            }
          }
        });

        connectObserver();
      }

      function init() {
        applyBadges();
        startObserver();
      }

      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
      } else {
        init();
      }
    })();
  </script>

  <style>
    :root {
      --variant-badge-top: -12px;
      --variant-badge-right: 10px;
      --variant-badge-font-size: 12px;
      --variant-badge-font-weight: 400;
      --variant-badge-line-height: 1.2;
      --variant-badge-text-color: #E02020; /* Badges' text color */
      --variant-badge-bg: #FFD700; /* Badges' background color */
      --variant-badge-border-color: #FFD700; /* Badges' border color color */
      --variant-badge-border-width: 1px;
      --variant-badge-border-radius: 5px;
      --variant-badge-padding-y: 2px;
      --variant-badge-padding-x: 4px;
      --variant-badge-letter-spacing: 0;
      --variant-badge-white-space: nowrap;
    }

    .variant-badge {
      {% comment %} position: absolute; {% endcomment %}
      top: var(--variant-badge-top);
      right: var(--variant-badge-right);
      font-size: var(--variant-badge-font-size);
      font-weight: var(--variant-badge-font-weight);
      line-height: var(--variant-badge-line-height);
      letter-spacing: var(--variant-badge-letter-spacing);
      color: var(--variant-badge-text-color);
      background: var(--variant-badge-bg);
      border: var(--variant-badge-border-width) solid var(--variant-badge-border-color);
      border-radius: var(--variant-badge-border-radius);
      padding: var(--variant-badge-padding-y) var(--variant-badge-padding-x);
      white-space: var(--variant-badge-white-space);
    }
    .tee-clipart-label .variant-badge{
        right: unset !important;
    }
    .variant-badge {
        margin-left: 10px;
    }
  </style>
{% endif %}
```

### 2. Connect the snippet to your Theme
*  Open the **Layout** folder and select `theme.liquid`.
*  Locate the closing `</head>` tag.
*  Paste the following render tag immediately above the `</head>` tag:

```
{% render 'teeinblue-custom-badges' %}
```

![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/monosnap-image-2026-03-20-16-2_3i0etg.png)


### 3. Customize Styles (Optional)
You can adjust the colors, background, and borders by modifying the CSS variables within the `<style>` section of your snippet file.

![](https://storage.crisp.chat/users/helpdesk/website/-/6/0/8/5/6085dc2a7293d800/monosnap-image-2026-03-20-16-2_10j3alb.png)


---

# Step 4: Verification

*  Open the product page on your storefront.
*  Verify that badges appear correctly next to the specified variant options.
*  Switch between different variant options to ensure badges update or disappear as expected.