less than a minute read • Updated

Manage product variants with Framer CMS (Advanced)

Use Framer CMS to manage variant groups, options and more.


Overview

By using Foxy and Framer CMS to manage products and product variants, you'll be able to add product variants and additional power features to your Framer setup.

This approach consists of two CMS collections. One collection for products and another collection for product variants. The two are connected with a multi-reference field.

Features

The following features are supported (more in the works):

  • Multiple levels of variant groups

  • Select field and radio buttons

  • Dynamically styled radio buttons

  • Chained variant functionality

  • Per variant combination inventory control

  • Real-time image change

  • Real-time price change

  • Real-time SKU change

Objectives

In this article, we'll accomplish the following:

  • Create a product variants collection in Framer CMS

  • Reference product variants from the products CMS collection

  • Set up variant group elements, select fields, and radio buttons in add-to-cart form

  • Configure variant snippet settings

Demo


Create Variants CMS Collection

An additional CMS collection is needed to store product variant data. Once you've created this additional CMS collection and have added data, you should have a CMS item for every possible product variant combination (ie: Awesome Shirt / Blue / Large).

  1. 1

    In Framer, create a new CMS Collection (name the collection as needed).

  2. 2

    Add the following CMS fields as needed (name of field can be whatever you want):


    Note: The following fields are optional unless you're integrating with Printful. For Printful, SKU, Image, and Price are required.

    NameType
    SKUPlain Text
    PriceNumber
    ImageImage
    InventoryNumber
    WeightNumber
  3. 3

    For each variant group (ie: Size, Color, Format), add a plain text field.

  4. 4

    In the Products CMS Collection, add a new multi-reference field connected to the new Variants CMS Collection.


Configure Add To Cart Form

You should have already set up add-to-cart forms following this article, which adds a product name and price fields at the minimum. To enable dynamic variants, you'll also need to add a product code (SKU) field:

  1. 1

    In the add-to-cart form on the Products Template Page, duplicate the product name hidden input element.

  2. 2

    In the element settings, change the Name to code (lowercase).

  3. 3

    Change the Value to your product code (SKU) CMS field. If there isn't one, you can use the Slug field.

If you need per-variant inventory control, follow the steps below:

  1. 1

    Duplicate the hidden input element again.

  2. 2

    In the element settings, change the Name to quantity_max (lowercase).


Add Variant Option Fields to the Form

Our variant functionality supports select fields and radio buttons (default and custom). All variant groups can use the same field type, or you can mix them as needed (ie: Color uses radio buttons, Size uses select field).

  1. 1

    In the add-to-cart form in the Products Template Page, create and design a field for each variant group.

  2. 2

    Navigate to the Assets tab.

  3. 3

    Open the code file for the Foxy code overrides (ie: Foxy.tsx).

  4. 4

    Copy the code snippet below:

    // Dynamic variants from CMS
    export function withFoxyVariantGroup(Component): ComponentType {
      return forwardRef((props, ref) => {
        return (
          <Component
            ref={ref}
            {...props}
            data-foxy-variant-group={props['data-framer-name'].toLowerCase()}
          />
        );
      });
    }
    
    export function withFoxyVarianItem(Component): ComponentType {
      return forwardRef((props, ref) => {
        return (
          <Component
            ref={ref}
            {...props}
            data-foxy-id="variant-item"
            style={{ display: 'none' }}
          />
        );
      });
    }
    
    export function withFoxyInventory(Component): ComponentType {
      return forwardRef((props, ref) => {
        return <Component ref={ref} {...props} data-foxy-product="inventory" />;
      });
    }
  5. 5

    In the code editor, paste the code snippet below any existing code.

  6. 6

    Go back to the Product Template Page designer.

Select Field

Select fields are recommended for variant groups with many options and/or that don't need option specific styling.

  1. 1

    Double click on the select field element.

  2. 2

    Rename the element to the variant group name (lowercase, no special characters, replace spaces with hyphens). For example: size or shoe-size.

  3. 3

    In the element settings, enter a Name for the field. This will be the option name shown in cart (ex: Size).

  4. 4

    Set Required to Yes.

  5. 5

    For Options, keep only one option with the settings below:
    - Value - empty
    - Title - Select...
    - Enabled - No
    - Default - Yes

  6. 6

    Scroll the Code Overrides section and click the + button.

  7. 7

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  8. 8

    For the Override field, choose withFoxyVariantGroup.

Radio Button

Radio buttons are recommended for variant groups that require options specific styling and/or that don't have many options.

  1. 1

    Double click on the radio button group element.

  2. 2

    Rename the element to the variant group name (lowercase, no special characters, replace spaces with hyphens). For example: color or pocket-color.

  3. 3

    In the element settings, click the + button in the Code Overrides section.

  4. 4

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  5. 5

    For the Override field, choose withFoxyVariantGroup.

  6. 6

    Inside of the radio button group element, keep only one radio button as a template.

  7. 7

    Click on the radio button element.

  8. 8

    In the element settings, enter a Name for the field. This will be the option name shown in cart (ex: Color).

  9. 9

    Set Checked to No.


Add Code Overrides to Elements

Apply the following code overrides to elements if you need real-time price, image or inventory display.

Price

  1. 1

    Click on the price element.

  2. 2

    In the element settings, click the + button in the Code Overrides section.

  3. 3

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  4. 4

    For the Override field, choose withFoxyPrice.

Image

  1. 1

    Click on the image element.

  2. 2

    In the element settings, click the + button in the Code Overrides section.

  3. 3

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  4. 4

    For the Override field, choose withFoxyImage.

Inventory

  1. 1

    Click on the element that displays inventory count.

  2. 2

    In the element settings, click the + button in the Code Overrides section.

  3. 3

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  4. 4

    For the Override field, choose withFoxyInventory.


Add Variant List Element

  1. 1

    Click the insert element button.

  2. 2

    Choose Fields > Variants (the multi-reference field that contains available variants).

  3. 3

    Add a filter to the variant list element (under Content in element settings).

  4. 4

    Configure the filter as the image below. For the Value field, set variable to the Variants field.

  5. 5

    Place the variant list element anywhere on the Products Template Page. This element will be hidden with a code override (applied in the next section) on the published site. Don't set its visibility to none.


Configure Variant Item Element

  1. 1

    Click on the variant item element.

  2. 2

    In the element settings, click the + button in the Code Overrides section.

  3. 3

    For the File field, choose the Foxy code overrides file (ie: Foxy).

  4. 4

    For the Override field, choose withFoxyVariantItem.

  5. 5

    Inside of the variant item element, insert an element for each variant info (ie: price, image, inventory, weight, SKU, size, color, etc.).

  6. 6

    For each variant info element, double click on the element and rename it to the variant name (lowercase, no special characters, replace spaces with hyphens), ie: price, image, inventory, weight, sku, size, color, etc. Note that for elements that connect with a variant group (ie: size, color), the element's name needs to be the same as the variant group name.


Add Variants Script

The variants script handles all the needed logic to make the variants functionality work.

  1. 1

    Go to Site Settings > Custom Code.

  2. 2

    Click the + button to add a new script.

  3. 3

    Configure the settings as follows:
    - Name: Foxy Variants (can be whatever you want)
    - Placement: End of <body>
    - Page: choose the product template page (ex: /products/:slug)
    - Run: Once

  4. 4

    Copy the snippet below and paste in the code editor:

<!-- FOXY VARIANTS -->
<script src="https://cdn-js.foxy.io/website-helpers@1/foxy-variants.js"></script>
<script>
  (() => {
    const config = {
      sortBy: "",
      sortOrder: "",
      priceDisplay: "low-high",
      pricePrecision: "2",
      defaultLocale: "en-US",
      defaultCurrency: "USD",
      inventoryControl: false,
      inventoryDefaultLabel: "Configure options for availability",
      selectUnavailableLabel: "Unavailable",
      forceReinit: true,
      adapter: ({ container, config, log }) => {
        document
          .querySelector('[data-foxy-product="form"]')
          .setAttribute('foxy-id', 'form');

        document
          .querySelector('[data-foxy-product="image"] img')
          ?.setAttribute('foxy-id', 'image');

        const priceEl = document.querySelector('[data-foxy-product="price"]');
        if (priceEl?.firstElementChild) {
          priceEl.firstElementChild.setAttribute('foxy-id', 'price');
          priceEl.removeAttribute('data-foxy-product');
        }

        document
          .querySelector('[data-foxy-product="inventory"] p')
          ?.setAttribute('foxy-id', 'inventory');

        document
          .querySelectorAll('[data-foxy-variant-group]')
          .forEach((el) =>
            el.setAttribute(
              'foxy-variant-group',
              el.getAttribute('data-foxy-variant-group')
            )
          );

        document
          .querySelectorAll('[data-foxy-id="variant-item"]')
          .forEach((itemEl) => {
            itemEl.setAttribute('foxy-id', 'variant-item');
            itemEl.querySelectorAll('[data-framer-name]').forEach((el) => {
              const name = el.getAttribute('data-framer-name')?.toLowerCase();
              if (!name) {
                return;
              }

              if (name === 'image') {
                const variantImageEl = el.querySelector('img');
                if (variantImageEl?.src) {
                  itemEl.setAttribute('foxy-variant-image', variantImageEl.src);
                }
              } else {
                itemEl.setAttribute(`foxy-variant-${name}`, el.textContent);
              }
            });
          });
      },
    };

    Foxy.variantsAutoInit(config);
  })();
</script>

Configure Variants Snippet

The default snippet configuration will work for most, but each option can be modified as needed. Please refer to the chart below for info on what each option does and supported values:

sortBy
Controls what options for each variant group should be sorted by.

  • "" (default) - Sorts by order items were added in CMS multi-reference field

  • "label" - Sorts by option label

  • "price" - Sorts by option price

sortOrder
Controls order options for each variant group should be listed in.

  • "" (default) - Sorts by order items were added in CMS multi-reference field

  • "ascending" - Ascending order

  • "descending" - Descending order

priceDisplay
Controls how pricing is displayed for your price display element on page load (when no variants have been chosen yet).

  • "low-high" (default) - Displays a low to high price range

  • "low" - Displays lowest price

  • "high" - Displays highest price

pricePrecision
Controls the number of decimal places.

  • Defaults to "2". Supports any integer number value.

defaultLocale
Controls language and regional preference.

  • Supports any standard language code (ie: en-US)

defaultCurrency
Controls currency used on page.

  • Supports any valid three-letter ISO 4217 currency code (ie: "USD", "EUR", "GBP")

inventoryControl
Controls whether variant inventory count should be considered.

  • true - Only in-stock variant combinations can be added to cart and purchased

  • false - Inventory count will be ignored and all variant combinations can be added to cart and purchased

inventoryDefaultLabel

When inventory control is enabled and an element is used to display available inventory, this is the text that will be displayed on page load (before customer configures variant options).

selectUnavailableLabel
When a specific option is unavailable, this is the text that will be displayed next to the option label in select fields.


Need Help?

Did this article answer your questions? Need help with anything? Please click below to contact us.