Build a Product Modal Using the Shopify Section Rendering API


Loading the Elevenlabs Text to Speech AudioNative Player…

Continuing our exploration of Shopify’s Section Rendering API (see previous blog here), today we are building a simple popup modal that shows product details utilizing this API. This simple example is a starting point for building some great, dynamic content utilizing this technology. Let’s get started.

Check out the full code here: https://github.com/ndrishinski/blogs/tree/master/section-render-api-modal

Prefer Video?

Enjoy in video format otherwise read on!

Create our Custom Section

In this tutorial we will be working within the Dawn theme. First we need to create our file under the sections folder, and name it custom-product-modal.liquid. We can first add the style tags with the given code:

<style>
  /* Modal Styles */
  #custom-modal {
    /* position: fixed; */
    z-index: 1;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    background-color: rgba(0, 0, 0, 0.5);
  }

  /* Modal Content Styles */
  .custom-modal-content {
    background-color: #fefefe;
    margin: 15% auto;
    padding: 20px;
    border: 1px solid #888;
    width: 50%;
    min-width: 450px;
    max-width: 600px;
    display: flex;
    border-radius: 4px;
  }

  /* Close Button Styles */
  .custom-close-modal {
    color: #aaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
  }

  .custom-close-modal:hover,
  .custom-close-modal:focus {
    color: black;
    text-decoration: none;
    cursor: pointer;
  }

  .shopify-section-template--21946272514334__image_banner {
    display: none;
  }


  /* flex stuff */
  .modal-left {
    flex: 1;
  }

  .modal-right {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  }

  .sneaky-submit {
    height: 40px;
    width: 110px;
  }

  .modal-rt {
    display: flex;
    flex: 1;
    justify-content: center;
    align-items: center;
    flex-direction: column;
  }

  #addToCartButton {
    background-color: rgba(var(--color-button), var(--alpha-button-background));
    appearance: none;
    border: 0;
    justify-content: center;
    align-items: center;
    padding: 0 3rem;
    font: inherit;
    text-decoration: none;
    color: rgb(var(--color-button-text));
    border-radius: 4px;
    cursor: pointer;
  }
</style>

Next we can add our HTML.

<div
  class="section-id"
  id="modal-section"
  data-section="{{ section.id }}"
  style="display: none;">
  <div id="custom-modal" class="custom-modal">
    <!-- Modal Content -->
    <div class="custom-modal-content">
      <div class="modal-left">
        <!-- Product Title -->
        <h2>{{ product.title }}</h2>
        <!-- Product Images -->
        {{ product.featured_image | image_url: width: 300 | image_tag }}
      </div>
      <div class="modal-right">
        <div class="modal-rt">
          <p>{{ product.description }}</p>
          <p>{{ product.price | money }}</p>
        </div>
        <div class="modal-rb">
          <input
            type="hidden"
            name="id"
            id="get_product_id"
            value="{{ product.variants.first.id }}">
          <button id="addToCartButton">Add to Cart</button>
        </div>
      </div>
      <!-- custom-close-modal Button -->
      <span class="custom-close-modal">&times;</span>
    </div>
  </div>
</div>

This HTML/Liquid shows the product’s title, featured image, description, price and add to cart button. Also of note is the image_tag which you can read here to learn more about. Notice that the container div has a style of display: none;, this is because we will render the section initially, but will manipulate the style via JavaScript when we actually want it to display. Next we can add our JavaScript.

<script>
  window.addEventListener("load", (event) => {
    async function openModal(html, shouldShow) {
      const modalHTML = html;
      if (shouldShow) {
          const replacingHTML = await document.querySelector("#modal-section");
          replacingHTML.outerHTML = html;
      }

      // Get references to the modal and close button
      const modal = document.getElementById("custom-modal");
      const closeButton =
        document.getElementsByClassName("custom-close-modal")[0];

      let tempy = document.querySelector("#modal-section")
      tempy.style.display = 'block'

    //   modal.style.display = "block";
      document.getElementById("custom-modal").style.position = "fixed";

      // Function to close the modal
      function closeModal() {
        modal.style.display = "none";
        modal.style.position = "static";
      }

      // Event listener for the close button
      closeButton.addEventListener("click", closeModal);

      // Event listener to close the modal when clicking outside of it

      window.addEventListener("click", function (event) {
        if (event.target == modal || event.target == closeButton) {
          closeModal();
        }
      });
    }

    document.addEventListener("click", async function (event) {
      if (event.target.matches(".modal-selector-quick-view")) {
        const targetData = event.target.dataset.target;
        let response = await fetch(
          `/products/${targetData}?section_id=<add your section ID here>`
        );
        let productMarkup = await response.text();
        openModal(productMarkup, true);
      } else if (event.target.matches('#addToCartButton')) {
        const id = document.querySelector('#get_product_id').value
        let formData = {
            'items': [{
            'id': id,
            'quantity': 1
            }]
        };
          fetch(window.Shopify.routes.root + 'cart/add.js', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(formData)
            })
            .then(response => {
                window.location.href = '/cart'
            return response.json();
            })
            .catch((error) => {
            console.error('Error:', error);
        });
      }
    });
  });
</script>

IMPORTANT! You need to get the Shopify Section ID and replace it in the JavaScript for this to work correctly. We’ll cover that in just a moment. But I want to point something out that perplexed me prior to creating this. The reason we have access to the product object in this section, is because in our fetch we are calling /products/${targetData} which will make the request from the products URL, where we will interpolate targetData with the product handle in the next step.

Add a Quick View Button to Open Modal

Next we need to add a button to open our modal, where we will also store the product handle that we reference in our API call. Open snippets/product-card.liquid and add:

...
<div class="card__content">
    <div class="card__information">
        <h4 style="z-index: 99; position: relative; cursor: pointer;" data-target="{{ card_product.handle}}" class="modal-selector-quick-view">Quick View</h4> {% comment %} <--- add here {% endcomment %}
    ...

Now our event listener has an element to watch for.

Add Section to Theme Customizer

In order to add this section via the Theme Customizer, we need to add the following schema to the bottom of the custom-product-modal.liquid:

{% schema %}
  {
    "name": "Quick View Modal",
    "limit": 1,
    "settings": [
      {
        "type": "checkbox",
        "id": "title",
        "label": "Text"
      }
    ],
    "presets": [
      {
        "name": "Quick View Modal",
        "settings": {
          "title": "Quick View Modal"
        }
      }
    ],
    "enabled_on": {
      "templates": ["*"]
    }
  }
{% endschema %}

After saving, we can add this to the homepage via the Theme Customizer:

Finding the Section ID

The last step here, is to find our section ID that we can replace in the JavaScript above. If we open up the inspector of our browser and search for “modal-section”, we can copy the section ID from the ‘data-section’ attribute. It should start with ‘template–‘.

And in our custom-product-modal.liquid file, we can add it to our JavaScript like so:

`/products/${targetData}?section_id=template--22031678636318__custom_product_modal_VGDTKG`

Conclusion

Now when we save, and open our preview we should have a fully functioning popup modal utilizing the Section Rendering API on our featured collection. I hope you enjoyed this tutorial and stay tuned for more Shopify development content!