javascripthtmlsnipcart

How do I create tiered custom attribute select boxes with SnipCart?


I am looking to have two custom attributes for products, where the second custom attribute has unique options depending on the first attribute selected.

My particular circumstance is selling art that will have many different formats and sizes, where the price of the sizes will be different depending on which format is selected (IE: Print, Framed, Canvas, etc.).

The obvious alternative is to just have different product listings for each format, and not have the double drop down menu's. However, that is not ideally what I am looking to do.

This is the code provided in the documentation for a single select box and custom attribute:

<label>Frame color</label>
<select id="frame_color">
  <option value="Black">Black</option>
  <option value="Brown">Brown</option>
  <option value="Gold">Gold</option>
</select>
<button
  id="starry-night"
  class="snipcart-add-item"
  data-item-id="starry-night"
  data-item-price="79.99"
  data-item-url="/paintings/starry-night"
  data-item-description="High-quality replica of The Starry Night by the Dutch post-impressionist painter Vincent van Gogh."
  data-item-image="/assets/images/starry-night.jpg"
  data-item-name="The Starry Night"
  data-item-custom1-name="Frame color"
  data-item-custom1-options="Black|Brown|Gold"
  data-item-custom2-name="Gift note">
  Add to cart
</button>
<script>
const button = document.querySelector('#starry-night')
const select = document.querySelector('#frame_color')
select.addEventListener('change', () => {
  // Sets the default frame color when adding the item
  button.setAttribute("data-item-custom1-value", select.value)
})
</script>

Solution

  • This can be done by having multiple products behind the scenes, but making it appear to the user that there is only one product (per item). Then, changing which products (and custom attribute selection boxes) are visible depending on the first selection box.

    I am a novice so there may be a simpler way to accomplish this, but this is what I came up with and it works well. Also, I am using a little jQuery in this code so it will require modifications to work without it.

    <style>
    .hidden{
      display:none;
    }
    </style>
    
    <select id="item-1">
        <option value="1">Type 1</option>
        <option value="2">Type 2</option>
    </select>
    
    <div id="type-1-1" class="item-content-1">
        <select id="size-1-1">
            <option value="8x8 ($50)">8x8 ($50)</option>
            <option value="12x12 ($100)">12x12 ($100)</option>
            <option value="20x20 ($200)">20x20 ($200)</option>
        </select>
        <button id="add-to-cart-1-1" class="snipcart-add-item"
            data-item-id="product-1-1"
            data-item-price="0.00"
            data-item-url="https://example.com"
            data-item-description="Product 1 type 1 description"
            data-item-image="/img.jpg"
            data-item-name="Product 1 type 1"
            data-item-custom1-name="Size"
            data-item-custom1-options="8x8 ($50)[+50.00]|12x12 ($100)[+100.00]|20x20 ($200)[+200.00]"
            data-item-custom1-value="8x8 ($50)"
            data-item-custom1-required="true">Add To Cart
        </button>
    </div>
    
    <div id="type-1-2" class="item-content-1 hidden">
        <select id="size-1-2">
            <option value="8x8 ($90)">8x8 ($90)</option>
            <option value="12x12 ($170)">12x12 ($170)</option>
            <option value="20x20 ($300)">20x20 ($300)</option>
        </select>
        <button id="add-to-cart-1-2" class="snipcart-add-item"
            data-item-id="product-1-2"
            data-item-price="0.00"
            data-item-url="https://example.com"
            data-item-description="Product 1 type 2 description"
            data-item-image="/img.jpg"
            data-item-name="Product 1 type 2"
            data-item-custom1-name="Size"
            data-item-custom1-options="8x8 ($90)[+90.00]|12x12 ($170)[+170.00]|20x20 ($300)[+300.00]"
            data-item-custom1-value="8x8 ($90)"
            data-item-custom1-required="true">Add To Cart
        </button>
    </div>
    
    <select id="item-2">
        <option value="1">Type 1</option>
        <option value="2">Type 2</option>
    </select>
    
    <div id="type-2-1" class="item-content-2">
        <select id="size-2-1">
            <option value="8x8 ($50)">8x8 ($50)</option>
            <option value="12x12 ($100)">12x12 ($100)</option>
            <option value="20x20 ($200)">20x20 ($200)</option>
        </select>
        <button id="add-to-cart-2-1" class="snipcart-add-item"
            data-item-id="product-2-1"
            data-item-price="0.00"
            data-item-url="https://example.com"
            data-item-description="Product 2 type 1 description"
            data-item-image="/img.jpg"
            data-item-name="Product 2 type 1"
            data-item-custom1-name="Size"
            data-item-custom1-options="8x8 ($50)[+50.00]|12x12 ($100)[+100.00]|20x20 ($200)[+200.00]"
            data-item-custom1-value="8x8 ($50)"
            data-item-custom1-required="true">Add To Cart
        </button>
    </div>
    
    <div id="type-2-2" class="item-content-2 hidden">
        <select id="size-2-2">
            <option value="8x8 ($90)">8x8 ($90)</option>
            <option value="12x12 ($170)">12x12 ($170)</option>
            <option value="20x20 ($300)">20x20 ($300)</option>
        </select>
        <button id="add-to-cart-2-2" class="snipcart-add-item"
            data-item-id="product-2-2"
            data-item-price="0.00"
            data-item-url="https://example.com"
            data-item-description="Product 2 type 2 description"
            data-item-image="/img.jpg"
            data-item-name="Product 2 type 2"
            data-item-custom1-name="Size"
            data-item-custom1-options="8x8 ($90)[+90.00]|12x12 ($170)[+170.00]|20x20 ($300)[+300.00]"
            data-item-custom1-value="8x8 ($90)"
            data-item-custom1-required="true">Add To Cart
        </button>
    </div>
    
    <script>
        var item_count = 2; //number of items in shop
        var type_count = 2; //number of type subdivisions
        var i = 1;
        for (i = 1; i <= item_count; i++) {
            const type_select = document.querySelector('#item-' + i);
            const count = i
            type_select.addEventListener('change', () => {
                $('.item-content-' + count).addClass("hidden");
                $('#type-' + count + "-" + type_select.value).removeClass("hidden");
            });
            var ii = 1;
            for (ii = 1; ii <= type_count; ii++) {
                const addToCart = document.querySelector('#add-to-cart-' + i + "-" + ii);
                const size = document.querySelector('#size-' + i + "-" + ii);
                size.addEventListener('change', () => {
                    addToCart.setAttribute("data-item-custom1-value", size.value);
                });
            };
        };
    </script>