Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 24

Creating a Persistent Mini-Cart

Recommended resources

Hello again!

In our last lesson, we mapped out the Shopify theme architecture, understanding how layouts, templates, sections, and snippets form a hierarchy to render a complete page. We saw that theme.liquid acts as the master frame, and the {{ content_for_layout }} tag is where page-specific content gets injected.

This raises an interesting question: What about UI elements that need to be on every page, like a shopping cart icon that opens a summary of the cart's contents? This feature, often called a "mini-cart" or "cart drawer," needs to persist across the entire customer journey.

Today, we'll build exactly that. Our learning outcome is to use the global cart object to create a persistent mini-cart across the theme. This lesson is a perfect fusion of concepts: it applies our knowledge of the theme hierarchy, introduces the global cart object for accessing data, and leverages your JavaScript skills to create a dynamic, app-like experience right within the theme.

This is a classic e-commerce feature, and understanding how to build it from first principles will be a cornerstone of your portfolio.

Types of Shopify Cart
This image shows various common cart interfaces in e-commerce. Our focus today will be on creating a "Slide Cart Drawer" or "Mini Cart" that is accessible from any page.

1. The Foundation: The Global cart Object and Placement

To display the cart's contents, we first need access to its data. Shopify provides a global Liquid object simply called cart that is available on every page of your storefront. This object contains all the information about the customer's current shopping cart.

Let's familiarize ourselves with its most important properties.

cart - Liquid objects

The Shopify Developer documentation is the definitive source for Liquid objects. Please review the properties of the cart object to understand the data we'll be working with.

In the 'Properties' section, focus on understanding item_count, items, total_price, and empty?. These are the core properties you will use constantly when dealing with the cart.

Now, where do we put the code for our mini-cart? Based on our last lesson, if we put it inside a page template (like product.json), it would only appear on product pages. To make it persistent, it needs to be part of the master layout.

The best practice is to:

  1. Create a new file in the sections directory (e.g., cart-drawer.liquid).
  2. Add the Liquid markup to this section to render the cart's contents using the cart object.
  3. Include this new section in layout/theme.liquid, typically just before the closing </body> tag. This ensures it's part of every page but sits outside the main content area controlled by {{ content_for_layout }}.

The following video demonstrates this initial setup perfectly.

Creating a Shopify ajax cart drawer

Let's watch how to create the Liquid structure for our cart drawer. This segment covers creating the section file, including it in theme.liquid, and using the cart object to loop through items and display totals.

Watch from 02:14 to 08:04. Pay attention to how a new section is created and then rendered in theme.liquid. Observe the use of cart.items, cart.item_count, and cart.total_price to build the basic structure.

At this point, you have a mini-cart that correctly displays the cart's contents on page load. But what happens when a user clicks "Add to Cart"? The page would reload, or nothing would happen to our drawer. This leads to a clunky user experience. We need to make it dynamic.


2. Making It Dynamic: The Shopify Ajax API

To create a smooth, modern experience, we need to update the cart without a full page refresh. Your experience with front-end frameworks like React and Next.js is highly relevant here. Just as you would use the fetch API to communicate with a backend and then update your application's state to re-render the UI, we'll do something very similar here using vanilla JavaScript and Shopify's specialized APIs.

The key is the Shopify Ajax API. It provides a set of endpoints that allow you to manage the cart from your theme's client-side JavaScript. The most common endpoints are:

  • /cart/add.js (POST): Adds an item to the cart.
  • /cart/change.js (POST): Changes the quantity of a line item.
  • /cart/update.js (POST): Updates multiple line items at once.
  • /cart.js (GET): Retrieves the entire cart object as JSON.

But how do we update the UI after a successful API call? We could manually build the new HTML in JavaScript, but that's tedious and error-prone. A much cleaner, modern approach is to use Shopify's Section Rendering API. This allows you to ask Shopify to re-render just a single theme section and return its new HTML.

By sending a fetch request to /?section_id=your-section-name, Shopify will return the complete, updated HTML for that section. We can then use JavaScript's .innerHTML to swap out the old content with the new.


3. Implementation: A Step-by-Step Guide

Let's walk through the full implementation, combining the Liquid section we've already defined with the JavaScript needed to make it interactive. We'll follow the same video, which provides an excellent, concise walkthrough of the entire process.

Step 1: Intercepting 'Add to Cart' and Opening the Drawer

First, we need to prevent the default form submission of our "Add to Cart" buttons and instead send an Ajax request. After the item is added, we'll update and open our drawer.

Creating a Shopify ajax cart drawer

This segment covers the initial JavaScript setup: selecting the 'add to cart' forms, preventing default submission, and making the fetch call to /cart/add.js.

Watch from 10:20 to 12:41. Focus on how event.preventDefault() is used and how new FormData(form) is passed as the body of the fetch request.

Step 2: Updating the Cart Drawer Content

This is the most critical step. After successfully adding an item, we need to fetch the new state of our cart drawer and display it.

Creating a Shopify ajax cart drawer

Now, let's implement the UI update. This part shows exactly how to use the Section Rendering API to get the drawer's new HTML and inject it into the DOM.

Watch from 18:01 to 22:51. Pay close attention to the fetch('/?section_id=cart-drawer') call. This is the Section Rendering API in action. Notice how the response text is parsed into an HTML element so its contents can be easily extracted and used to update the on-page drawer.

Test your understanding!

After replacing the cart drawer's innerHTML with the newly fetched HTML, you notice that your 'close' button and 'remove item' buttons inside the drawer no longer work. What is the likely cause of this issue, and what is the general solution?

Show answer

The likely cause is that the original event listeners attached to those buttons were discarded when their parent element's innerHTML was replaced. The new buttons, even if they look identical, are new DOM nodes and do not have the old listeners.

The solution is to re-attach the event listeners after you update the innerHTML. This usually involves creating a dedicated function (e.g., addCartDrawerListeners()) that attaches all necessary listeners (for closing, quantity updates, etc.) and calling this function both on initial page load and immediately after successfully re-rendering the cart drawer content. The video (LINK) addresses this exact problem starting around the 25:30 mark.

Step 3: Handling Quantity Updates and Removals

The same principles apply to updating item quantities or removing them. We'll add event listeners to our new quantity buttons, call the /cart/update.js endpoint, and then trigger our updateCartDrawer() function to re-render the section.

Creating a Shopify ajax cart drawer

Let's complete the functionality by implementing quantity adjustments. This final piece will make our cart drawer fully interactive.

Watch from 22:51 to 36:35. This is a longer segment, but it covers several important details: Creating a function to re-attach all event listeners to the new cart drawer content. Attaching click events to the plus/minus quantity buttons. Traversing the DOM to find the correct line_item.key for the item being updated. Making a fetch request to /cart/update.js with the new quantity. Calling the same updateCartDrawer() function to refresh the UI.


4. An Alternative: Bundled Section Rendering

The method we just implemented is excellent and works well: one Ajax request adds the item, and a second one fetches the updated section HTML.

However, Shopify offers an even more efficient method called Bundled Section Rendering. With this approach, you can tell an Ajax API endpoint (like /cart/change.js) to return the rendered HTML for one or more sections within the same response.

You do this by including a sections key in your JSON payload.

{
  "line": 1,
  "quantity": 3,
  "sections": ["cart-drawer", "cart-icon-bubble"]
}

The response will then contain a sections object with the rendered HTML for each section you requested. This saves an entire HTTP request, making your storefront faster and more efficient.

Section Rendering API & Bundled Section Rendering - How to Render Sections Asynchronously in Shopify

For a deeper understanding of this advanced technique, this video explains the concept of Bundled Section Rendering clearly.

Watch from 12:49 to 18:51. The presenter explains how the Dawn theme uses this technique on the cart page. Focus on understanding the payload of the request to /cart/change.js, which includes the sections array, and see how the response contains the rendered HTML, eliminating the need for a second fetch call.

While we used the two-request method in our main implementation, knowing about Bundled Section Rendering is crucial for optimizing your themes and demonstrates a deeper level of expertise.


Conclusion

In this lesson, we built one of the most essential features of any e-commerce site: a persistent, dynamic mini-cart. You have successfully integrated Liquid data objects with client-side JavaScript to create a seamless user experience that is standard in modern web development.

Key Takeaways:

  • The cart Object is Global: You can access cart data (items, total_price, etc.) on any page using the cart Liquid object.
  • Placement is Key for Persistence: To make a UI element appear on every page, create it as a section and include it directly in layout/theme.liquid.
  • Dynamic Updates require the Ajax API: Use fetch with endpoints like /cart/add.js and /cart/change.js to modify the cart without a page reload.
  • The Section Rendering API is for UI Updates: The most efficient way to update the mini-cart's HTML is to request a re-rendered version from Shopify using the Section Rendering API (/?section_id=...) or Bundled Section Rendering.
  • Remember to Re-bind Events: When you replace HTML using .innerHTML, any existing event listeners are lost. You must re-run your code that attaches event listeners to the new elements.

We have now built several key components of a theme. But how do we give merchants the power to customize them without touching code? In our next lesson, we will dive into the heart of Shopify's customization power: we will define a section's schema using a range of input settings (text, image_picker, color). This is how you transform a static section into a flexible, merchant-friendly content block.