Shopify 2.0 introduced a lot of new and exciting features including sections everywhere, the new shopify CLI, native metafields, and a shiny new starter theme called Dawn. The approach taken with Dawn is drastically different from the one taken with the older starter theme. Dawn no longer uses scss. Dawn also no longer uses jQuery and relies on pure javascript. The developers also decided to use partials versus loading one giant js and css global file. The idea is to only load what you need on a page by page basis.
Since Dawn is fairly new, there isn’t much documentation or community articles on it yet. The first thing I noticed is the need for a minicart. Dawn ships with a notification drawer, but no true minicart. This is usually a short and simple task with the older approach with the cart api, but I wanted to stay true to Dawn’s approach for rendering dynamic sections and use as much of the native code as possible. So, let’s jump into it.
Step 1
With a fresh new install of the Dawn theme running locally through the Shopify CLI, we need to open and adjust the cart.js located in the assets folder. First we need to understand how sections are being requested and dynamically rendered. Locate the getSectionsToRender method. This array of objects is used in the fetch request to the cart page and to target what elements on the dom will be updated. The request to cart/update, cart/change, and cart/add api request uses this array of objects to build an array of section IDs to pass into it.
https://shopify.dev/api/liquid/objects/routes#routes-cart_change_url
https://shopify.dev/api/ajax/reference/cart#post-cart-change-js
https://shopify.dev/api/ajax/reference/cart#bundled-section-rendering
section: document.getElementById('main-cart-items').dataset.id || 'main-cart-items', section: document.getElementById('main-cart-footer').dataset.id || 'main-cart-footer',
Since we are including the cart on every page, we will not have the dynamic section id, so we can hook into the default section title from cart.liquid template. To solve this, we can add the OR conditionals to the end of the sections in the getSectionsToRender method above.
Step 2
Move all of main-cart-items.liquid contents (aside from schema) to a snippet and render into main-carts-items.liquid. This will make the code more portable/reusable.
Step 3
Create a mini-cart.liquid snippet and render cart-items snippet (you will also need to render this within the main-cart-items.liquid as well). Make sure to include the cart.js and all styling within this snippet.
Step 4
Now we need to handle the main-cart-footer.liquid section content. We could place this in a snippet, but there are a few dynamic blocks within this section. Consider doing a little bit of refactoring here or copy all of the content from this section and paste into the mini-cart.liquid snippet (after the cart-items render). You will have to remove the schema from the snippet and remove the conditional rendering of blocks. You will also need to wrap the inline script from the footer into a script tag.
Important Note: In order for the footer messaging and price to work in the mini cart, you will need to make sure that the main-cart-footer.liquid includes default settings:
"default": { "blocks": [ { "type": "subtotal" }, { "type": "buttons" } ] }
Step 5
Conditionally render the newly created mini-cart.liquid snippet in theme.liquid layout. Congratulations! The cart markup is now on all pages. You can now adjust the count and remove items from the cart. BUT, we still need to solve for when a shopper adds to cart from a product page.
Step 6
We now need to make a few adjustments to the product-form.js in the assets folder. Add the following below the this.cartNotification.renderContents call.
this.cartNotification.renderContents(parsedState);
// added for minicart
document.querySelector('cart-items')?.classList.toggle('is-empty', parsedState.item_count === 0);
document.getElementById('main-cart-items')?.classList.toggle('is-empty', parsedState.item_count === 0); document.getElementById('main-cart-footer')?.classList.toggle('is-empty', parsedState.item_count === 0);
This is to toggle the empty class on the mini cart if the cart has items in it and handles the show/hide of cart state messaging (The same code can be found in the native cart.js).
Step 7
Notice that product-form.js queries for the cart-notifications custom element. This allows us to hook into the methods from that custom element and call renderContents for cartNotifications. To follow the breadcrumbs, open cart-notifications.js. We just need to add the last 2 objects to the sections to render (main-cart-items and main-cart-footer). Now, on add to cart on a product page, the mini-cart updates!
getSectionsToRender() {
return [
{
id: 'cart-notification-product',
selector: `#cart-notification-product-${this.productId}`,
},
{
id: 'cart-notification-button'
},
{
id: 'cart-icon-bubble'
},
{
id: 'main-cart-items',
section: 'main-cart-items',
selector: '.js-contents',
},
{
id: 'main-cart-footer',
section: 'main-cart-footer',
selector: '#main-cart-footer',
}
];
}
Step 8
The only thing left to do is stylize your mini cart with css and add a few custom script event listeners. To get the layout you want, I would recommend using css grid to place line items however you need them. You can wrap your mini-cart snippet with div and you can then toggle an open/closed class on the minicart. With some slick css you can show/hide and animate your cart on close and open. To open the mini-cart on a successful add to cart, simply add a line of custom code in the product-form.js in the finally portion of the request to do so.
You will also need to prevent default actions when clicking the cart count bubble link and toggle the open close class on the minicart.
Important Links:
https://shopify.dev/api/liquid/objects/routes#routes-cart_change_url
https://shopify.dev/api/ajax/reference/cart#post-cart-change-js
https://shopify.dev/api/ajax/reference/cart#bundled-section-rendering
Cool Links:
https://cssgrid.io/
https://shopify.dev/themes/navigation-search/search/predictive-search