Building a Mini Cart
Tags that this post has been filed under.
This tutorial will teach you how to use HTML5 semantics and web patterns to implement a mini cart.
What is a mini cart?
In eCommerce we refer as mini cart to the icon that's on the header of the website that indicates the amount of items that are currently on the cart.
At any given moment this element can be:
- Empty: the icon is displayed with or without the number of items in the cart (zero elements in the cart).
- With items: some sort of visual indicator is displayed to let the users know that there are elements in the cart. Typically the number of items in the cart are displayed on top of the icon.
Styling
This element is - depending on the icon used - really small. The most common icon a shopping cart (or basket) is no bigger than 20px.
A large enough target size should be defined to make sure users can easily activate the mini cart. Best practices recommends using a target size of 44px.
To learn more about Target Size read: Success Criteria 2.5.5
This can be achieved using a mix of icon size + padding. Let's suppose the icon has a size of 20px by 20px. The remaining space 24px should be padding.
Calculation:
(width - icon size = padding)
(44px - 20px = 24px).
The badge or items in cart icon notification, should be a floating element on top of the icon. It should be flexible enough to accommodate for single or multiple digits: 1 item vs 12 items in the cart.
.mini-cart {
padding: 24px;
display: inline-block;
position: relative;
}
.mini-cart .icon {
height: 20px;
width: 20px;
display: inline-block;
}
.mini-cart .badge {
font-size: 11px; // ** Note 1
min-width: 17px; // ** Note 2
padding: 3px 6px;
position: absolute;
}
Note 1: I don't like using small font sizes like 11px as they are really hard to read, however I understand the need to use small font size for this notification indicator to accommodate for design specifications.
Note 2: As this element data is dynamic I pay special attention to the width. I recommend using min-width and allowing the element to grow with content. Just need to make sure to align with the team on the alignment of this item when it expands.
Interaction
Depending on the website, the mini cart will have different actions on user interaction, and based on these actions the pattern required to make it work will vary. Based on this,I like to classify the mini-cart into three types:
- Open a link
- Display a cart summary
- Display the entire cart
Mini Cart Type 1: Open a link
In this scenario the user will be redirected to the Shopping Cart page.
- The user should be able to activate (click) this element and be redirected to the Shopping Cart page.
- The component should reflect the number of elements in the cart at any given time.
- Element should be focusable with the keyboard (and only one stop)
Screen readers considerations
-
This element does not have any other visual text other than the number of items in the cart. To give a better description to the mini cart
aria-label
is recommended. Example:aria-label="Basket has 1 item"
-
The elements "icon" & "badge" (cart count) should be hidden from the Screen Readers to avoid duplicated announcement.
-
Hiding elements from the Screen Reader in this case, will also avoid having more than one stop while navigating.
Note: When using aria-label
the authored text must be translated. For example: it should read "Basket with 2 items" or "Panier contenant 2 articles" for English or French respectively.
<a aria-label="Basket with 2 items" href="/cart">
<span aria-hidden="true">2</span>
<span aria-hidden="true" class="cart-icon">
<svg ... ></svg>
</span>
</a>
Mini Cart Type 2: Display Cart Summary
The second pattern - that's common for the mini cart - is displaying a shopping cart summary on hover
.
This creates blockers for users that don't use pointer devices (mouse) as there's no action for hover in most devices without pointer.
The best option is to change the behaviour from hover
to click
. This will improve the number of supported devices while also making sure that the cart summary is only displayed on user's intent, not when the pointer happens to be on the mini cart area while scrolling.
Screen reader considerations
One thing to notice with this pattern is that we're forcing users to click at least two times before they can visit the cart. First click opens the cart summary, second click opens a new URL.
This can be taxing for screen reader and keyboard users; once the cart summary is displayed they will need to traverse the cart summary before being able to click on the "View Cart" link.
We could optimize this by setting the focus on the "View Cart" link the moment the mini cart is displayed (following the Modal pattern).
However, when doing focus management the cart summary is skipped which is not the intent of this pattern. The intent of this mini cart is to display the cart summary to all users and then let them visit the cart or close the summary.
We're left with two options that are far from ideal:
- Force screen reader users to traverse through all the cart summary before they can find a link to the cart.
- Skip the cart summary to prevent multiple clicks, while not informing users that there's content they might not have perceived (cart items).
This is a conundrum that I don't know how to solve at the moment. My best advice is to skip this pattern altogether and choose Pattern #1 - Open a link.
There will be projects where this mini cart is required to be developed - aside from our advice to avoid it - what web pattern shall we use then?
Implementation
I had trouble determining which element to use to implement this pattern. One thing I was sure is that the previous solution was no longer suitable. The mini cart is no longer a link, it should be a button that displays some content on interaction.
I first considered Menu. But a menu is meant to trigger an action from a set, and choosing a single cart item implies that the user will do something with that single cart item. Since a menu is meant to replicate a native OS control, this is not a great fit.
Well, maybe it's a Combobox.
Combobox: an input widget with an associated popup that enables users to select a value for the combobox from a collection of possible values.
Combobox widgets are useful for acquiring user input. However, there's no selection or text input we need from the user in this case. This is not a great fit either.
Lastly I thought about Dialog (Modal).
A dialog is a window overlaid on either the primary window or another dialog window.
The mini cart could be a <button>
and the cart summary can have role="dialog"
. But then it will have to block users from interacting with content outside the active dialog window until it's closed. And it will also require a close button.
It wasn't until Adrian Roselli pointed that this is actually a Disclosure widget that I learned about this pattern. Shame on me!
A disclosure is a widget that enables content to be either collapsed (hidden) or expanded (visible). It has two elements: a disclosure button and a section of content whose visibility is controlled by the button.
This is exactly what I think should be used for this scenario. I would recommend reading Disclosure widget by Adrian Roselli to learn more about this pattern.
Complement that reading with ARIA Authoring Practices Guide on Disclosure (Show/Hide).
<button aria-label="Basket with 2 items" type="button" aria-expanded="false" aria-controls="cart-summary">
<span aria-hidden="true">2</span>
<span aria-hidden="true" class="cart-icon">
<svg ... ></svg>
</span>
</button>
<div id="cart-summary" aria-hidden="true"> ... </div>
Mini Cart Type 3: Display the entire cart
In this scenario the Cart starts hidden from the screen until the user clicks the mini-cart. Only then the Cart is displayed as a "Flyout" / "Drawer" / "Window" coming from the right of the page.
We currently don't have an HTML5 element that can do this, but we do have web pattern that represents this behaviour. A Dialog (Modal).
Even though visually it doesn't look like the regular Modal it is the closest representation of this interaction.
The good news is that in regards to the mini cart we should use the same solution as Method 2. The mini cart should be a <button>
.
The biggest difference here is that we'll be opening a modal and that has more complexities in HTML, CSS, ARIA & JavaScript coding.
According to WAI-ARIA practices guide:
"A dialog is a window overlaid on either the primary window or another dialog window. Windows under a modal dialog are inert. That is, users cannot interact with content outside an active dialog window."
Learn more about Dialog (Modal) by ARIA Authoring Practices Guide (APG).
We are fitting the entire cart into a Modal, and that comes with consequences. The mini cart evolved - from an atomic element - to an organism / feature that will have integration with many interfaces and elements to make it work.
This implementation will require multiple elements inside a modal:
- Close button
- Title element
- List of items in the cart
- Buttons to update quantity
- Buttons to remove elements
- Link to checkout
- and many more
We must also understand that this modal:
- Introduces confusion to a large amount of the population that's expecting to see the cart page
- Reduces the visibility of items in the cart
- Increases the difficulty to provide cross-sells and up-sell widgets
- Increases complexity on implementation.
<button aria-label="Basket with 2 items" type="button" aria-expanded="false" aria-controls="cart">
<span aria-hidden="true">2</span>
<span aria-hidden="true" class="cart-icon">
<svg ... ></svg>
</span>
</button>
<div id="cart" role="dialog" aria-modal=true"> ... </div>
Note: regarding aria-modal
applying the aria-modal property to the dialog element replaces the technique of using aria-hidden on the background for informing assistive technologies that content outside a dialog is inert. However I have found that this technique does not work for every implementation, test carefully and thoroughly.
Conclusion
After this extended article we can conclude that literally the mini cart is just an icon in the header. But practically, it depends. It requires different solutions depending on the type of Cart the website will use.
The mini cart should be either an anchor link <a>
or a <button>
. The most practical of them all - in my personal opinion - is a link to the Shopping Cart page. The other two patters (type 2 - show summary or type 3 - show cart) bring with them a lot of complexities and blockers from the technical & accessibility perspective.
Whatever your project decides to do, just make sure to use the proper element and pattern for this element and test with People with Disabilities.
Let's listen to the community and their experiences. eCommerce is not a commodity, it's a life requirement for many as the Pandemic showed us.
I would love to hear which of these three types of carts you prefer to use. Shoot me a message at @a11y_tips.