Add messages to mini cart
This tutorial shows you how to add inline and overlay feedback messages that appear in the mini cart when products are added or updated to the cart. These messages provide visual feedback to shoppers about their cart actions.
Inline messages appear at the top of the mini cart for a brief period (three seconds by default) and then automatically disappear, providing immediate feedback to users about their cart actions.
Overlay messages are displayed at the top center of the mini cart with a semi-transparent background when the same events occur.
You can customize the appearance and behavior of the inline and overlay messages by modifying the following:
Message text: Update the translations in the the content placeholders sheet under the
Cart.MiniCart.Message
namespace.Message styling: Modify the CSS classes in
commerce-mini-cart.css
. The styles use design tokens (prefixed with--
) to maintain consistency with the design system. Overlays can be customized as follows:- Background opacity using the alpha value in the overlay’s
background-color
(default is 50%) - Message position using the
top
,left
, andtransform
properties - Colors, spacing, shadows, and other visual properties using design tokens
- Background opacity using the alpha value in the overlay’s
Message position: For inline messages, change where the message appears in the mini cart by modifying the insertion point in the DOM.
Display duration: Change the timeout value in the
showMessage
function (default is 3000ms).
Prerequisites
Before implementing inline messages, ensure you have:
- Access to the content folder to manage message localization through placeholders.
- Understanding of the design system tokens used in the Commerce boilerplate template.
- The
commerce-mini-cart.css
file in yourblocks/commerce-mini-cart/
directory.
Events
The inline and overlay messages respond to two cart events:
cart/product/added
: Triggered when products are added to the cartcart/product/updated
: Triggered when products in the cart are updated
Implementation
To add inline or overlay messages to your mini cart, follow these steps:
Retrieve translations for message texts using placeholders
Get translations for custom messages from the content folder.
const placeholders = await fetchPlaceholders();
// Access the message texts from the Cart.MiniCart.Message namespaceconst MESSAGES = { ADDED: placeholders?.Cart?.MiniCart?.Message?.added, UPDATED: placeholders?.Cart?.MiniCart?.Message?.updated,};
Create the appropriate message containers
Inline messages require a container for the update message and a shadow wrapper to display the message. Overlay messages require an overlay container and a message container.
// Create a container for the update messageconst updateMessage = document.createElement('div');updateMessage.className = 'commerce-mini-cart__update-message';
// Create a shadow wrapperconst shadowWrapper = document.createElement('div');shadowWrapper.className = 'commerce-mini-cart__message-wrapper';shadowWrapper.appendChild(updateMessage);
// Create an overlay containerconst overlay = document.createElement('div');overlay.className = 'commerce-mini-cart__overlay';
// Create a message containerconst messageContainer = document.createElement('div');messageContainer.className = 'commerce-mini-cart__message';
overlay.appendChild(messageContainer);
Create a function to show and hide messages
Create a function that displays the message in the container and then hides it after a specified duration, such as three seconds.
const showMessage = (message) => { updateMessage.textContent = message; updateMessage.classList.add('commerce-mini-cart__update-message--visible'); shadowWrapper.classList.add('commerce-mini-cart__message-wrapper--visible'); setTimeout(() => { updateMessage.classList.remove('commerce-mini-cart__update-message--visible'); shadowWrapper.classList.remove('commerce-mini-cart__message-wrapper--visible'); }, 3000);};
const showMessage = (message) => { messageContainer.textContent = message; overlay.classList.add('commerce-mini-cart__overlay--visible'); setTimeout(() => { overlay.classList.remove('commerce-mini-cart__overlay--visible'); }, 3000);};
Add event listeners for cart updates
Listen for the cart/product/added
and cart/product/updated
events and display the appropriate message.
import { events } from '@dropins/tools/event-bus.js';
events.on('cart/product/added', () => showMessage(MESSAGES.ADDED), { eager: true,});events.on('cart/product/updated', () => showMessage(MESSAGES.UPDATED), { eager: true,});
Insert the message container into the mini cart block
Add the message container to the mini cart block to display the messages.
// Find the products container and add the message div at the topconst productsContainer = block.querySelector('.cart-mini-cart__products');if (productsContainer) { productsContainer.insertBefore(shadowWrapper, productsContainer.firstChild);} else { console.info('Products container not found, appending message to block'); block.appendChild(shadowWrapper);}
block.appendChild(overlay);
Update the CSS styles
Add styles to your commerce-mini-cart.css
file.
.commerce-mini-cart__update-message { display: none; font: var(--type-body-2-default-font); letter-spacing: var(--type-body-2-default-letter-spacing);}
.commerce-mini-cart__message-wrapper { background-color: var(--color-positive-200); border-radius: var(--shape-border-radius-1); padding: var(--spacing-xsmall); display: none; margin-bottom: var(--spacing-small);}
.commerce-mini-cart__message-wrapper--visible,.commerce-mini-cart__update-message--visible { display: block;}
.commerce-mini-cart__overlay { background-color: rgb(0 0 0 / 50%); display: none; position: absolute; inset: 0; z-index: 1000; border-radius: var(--shape-border-radius-1);}
.commerce-mini-cart__message { background-color: var(--color-positive-200); border-radius: var(--shape-border-radius-1); padding: var(--spacing-small); position: absolute; top: var(--spacing-medium); left: 50%; transform: translateX(-50%); font: var(--type-body-2-default-font); letter-spacing: var(--type-body-2-default-letter-spacing); box-shadow: var(--shape-shadow-3); width: 90%; max-width: 400px; text-align: center;}
.commerce-mini-cart__overlay--visible { display: block;}
Complete example
Here’s a complete example of implementing inline and overlay messages in your commerce-mini-cart.js
block file:
import { render as provider } from '@dropins/storefront-cart/render.js';import MiniCart from '@dropins/storefront-cart/containers/MiniCart.js';import { events } from '@dropins/tools/event-bus.js';
// Initializersimport '../../scripts/initializers/cart.js';
import { readBlockConfig, fetchPlaceholders } from '../../scripts/aem.js';import { rootLink } from '../../scripts/scripts.js';
export default async function decorate(block) { const { 'start-shopping-url': startShoppingURL = '', 'cart-url': cartURL = '', 'checkout-url': checkoutURL = '', } = readBlockConfig(block);
// Get translations for custom messages const placeholders = await fetchPlaceholders();
const MESSAGES = { ADDED: placeholders?.Cart?.MiniCart?.Message?.added, UPDATED: placeholders?.Cart?.MiniCart?.Message?.updated, };
// Create a container for the update message const updateMessage = document.createElement('div'); updateMessage.className = 'commerce-mini-cart__update-message';
// Create shadow wrapper const shadowWrapper = document.createElement('div'); shadowWrapper.className = 'commerce-mini-cart__message-wrapper'; shadowWrapper.appendChild(updateMessage);
const showMessage = (message) => { updateMessage.textContent = message; updateMessage.classList.add('commerce-mini-cart__update-message--visible'); shadowWrapper.classList.add('commerce-mini-cart__message-wrapper--visible'); setTimeout(() => { updateMessage.classList.remove('commerce-mini-cart__update-message--visible'); shadowWrapper.classList.remove('commerce-mini-cart__message-wrapper--visible'); }, 3000); };
// Add event listeners for cart updates events.on('cart/product/added', () => showMessage(MESSAGES.ADDED), { eager: true, }); events.on('cart/product/updated', () => showMessage(MESSAGES.UPDATED), { eager: true, });
block.innerHTML = '';
// Render MiniCart first await provider.render(MiniCart, { routeEmptyCartCTA: startShoppingURL ? () => rootLink(startShoppingURL) : undefined, routeCart: cartURL ? () => rootLink(cartURL) : undefined, routeCheckout: checkoutURL ? () => rootLink(checkoutURL) : undefined, routeProduct: (product) => rootLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), })(block);
// Find the products container and add the message div at the top const productsContainer = block.querySelector('.cart-mini-cart__products'); if (productsContainer) { productsContainer.insertBefore(shadowWrapper, productsContainer.firstChild); } else { console.info('Products container not found, appending message to block'); block.appendChild(shadowWrapper); }
return block;}
import { render as provider } from '@dropins/storefront-cart/render.js';import MiniCart from '@dropins/storefront-cart/containers/MiniCart.js';import { events } from '@dropins/tools/event-bus.js';
// Initializersimport '../../scripts/initializers/cart.js';
import { readBlockConfig, fetchPlaceholders } from '../../scripts/aem.js';import { rootLink } from '../../scripts/scripts.js';
export default async function decorate(block) { const { 'start-shopping-url': startShoppingURL = '', 'cart-url': cartURL = '', 'checkout-url': checkoutURL = '', } = readBlockConfig(block);
// Get translations for custom messages const placeholders = await fetchPlaceholders();
const MESSAGES = { ADDED: placeholders?.Cart?.MiniCart?.Message?.added, UPDATED: placeholders?.Cart?.MiniCart?.Message?.updated, };
block.innerHTML = '';
// Render MiniCart first await provider.render(MiniCart, { routeEmptyCartCTA: startShoppingURL ? () => rootLink(startShoppingURL) : undefined, routeCart: cartURL ? () => rootLink(cartURL) : undefined, routeCheckout: checkoutURL ? () => rootLink(checkoutURL) : undefined, routeProduct: (product) => rootLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), })(block);
// Create overlay container const overlay = document.createElement('div'); overlay.className = 'commerce-mini-cart__overlay';
// Create message container const messageContainer = document.createElement('div'); messageContainer.className = 'commerce-mini-cart__message';
overlay.appendChild(messageContainer); block.appendChild(overlay);
const showMessage = (message) => { messageContainer.textContent = message; overlay.classList.add('commerce-mini-cart__overlay--visible'); setTimeout(() => { overlay.classList.remove('commerce-mini-cart__overlay--visible'); }, 3000); };
// Add event listeners for cart updates events.on('cart/product/added', () => showMessage(MESSAGES.ADDED), { eager: true, }); events.on('cart/product/updated', () => showMessage(MESSAGES.UPDATED), { eager: true, });
return block;}
And here’s the accompanying CSS file (commerce-mini-cart.css
):
.commerce-mini-cart__update-message { display: none; font: var(--type-body-2-default-font); letter-spacing: var(--type-body-2-default-letter-spacing);}
.commerce-mini-cart__message-wrapper { background-color: var(--color-positive-200); border-radius: var(--shape-border-radius-1); padding: var(--spacing-xsmall); display: none; margin-bottom: var(--spacing-small);}
.commerce-mini-cart__message-wrapper--visible,.commerce-mini-cart__update-message--visible { display: block;}
.commerce-mini-cart__overlay { background-color: rgb(0 0 0 / 50%); display: none; position: absolute; inset: 0; z-index: 1000; border-radius: var(--shape-border-radius-1);}
.commerce-mini-cart__message { background-color: var(--color-positive-200); border-radius: var(--shape-border-radius-1); padding: var(--spacing-small); position: absolute; top: var(--spacing-medium); left: 50%; transform: translateX(-50%); font: var(--type-body-2-default-font); letter-spacing: var(--type-body-2-default-letter-spacing); box-shadow: var(--shape-shadow-3); width: 90%; max-width: 400px; text-align: center;}
.commerce-mini-cart__overlay--visible { display: block;}