Developing an Accessible ‘Add To Cart’ Flow

By Nic Chan

A small introduction

  • Freelance front-end developer
  • Worked on Shopify stores
  • Definitely a cat person

Talk format

  • 4 Patterns:
    • Buttons
    • Inline Notifications
    • Toasts
    • Dialogs
  • Different iterations, advantages and pitfalls
  • Tips and tricks

A typical product page

Wireframe of a typical product page. There are breadcrumbs on top, a series of images with thumbnails to the left, and a product title, price, purchase form and description on the right

HTML forms, all the way down

  1. Progressive Enhancement
  2. Semantics
    1. Wireframe of a product form, there is a fieldset for 'Color' with two options, 'Red' or 'Blue', and an 'Add to cart' button

The 'button' pattern

Two buttons, the first one says 'Add to cart' and the second one says 'Added to cart' with a checkmark next to it.

Good for zoom users!

Zoomtext being used on the product page, only the form and a bit of the description are visible.

ZoomText centered on a button

Zoomtext on the product page, the Add to Cart button now says 'Adding'.

We can't rely on just changing the text of our button


	addToCart(item).then(() => {
		const button = document.getElementById('add-to-cart');
		button.innerText = 'Adding...'

Live regions with buttons


	addToCart(item).then(() => {
		const liveRegion = document.getElementById('live-region');
		const button = document.getElementById('add-to-cart');
		liveRegion.innerText = 'Adding...'
		button.innerText = 'Adding...'

disabled or aria-disabled?


Consider your wording

Button with text changing from 'Add To Cart' to 'Adding...' and then back to the original 'Add to Cart'
Button with text changing from 'Add To Cart' to 'Adding' to 'Added to Cart' with a checkmark next to it.

Inline Notifications

Product form with a notification that says 'A Delightful Product has been added to your cart' below the 'Add to Cart' button

Should we use live regions for inline notifications?

A Delightful Product has been added to your cart

	addToCart(item).then(() => {
		const notification =
		notification.innerText =
			`${item.title} has been added to your cart`

Interactive Child Elements

Product form with an inline notification: 'A Delightful Product has been added to your cart.' Below the paragraph text, there are two links for 'Continue shopping' and 'View cart.'

Placement Options

Product page with an inline notification above the images and product form, below the breadcrumbs
Product page with an inline notification above the add to cart button.

A word of warning about toasts

Toasts and dialogs are fundamentally different

An introduction to toasts

The same product page, the 'A Delightful Product has been added to your cart' now shows up in a toast message on the upper right.

Should we be using toasts?

The same product page with a toast, except the toast disappears automatically after a second or so.

Toast solutions

Example of a notification drawer, with a heading of Your Notifications and a list of previous notifications with a timestamap
Example of a settings pageg, where you can select the notification timing


A Windows 98 style dialog showing the results of a registry scan. 'The system has been backed up already today, would you like to back it up again?' 'Yes' or 'No'

This is a dialog

Product page with a notification in the top right, similar to the toast example, except there is now an X button.

This is also a dialog

Product page with a modal in the middle of the page, alerting the user that an item has been added to the cart and offering the choice between 'View cart' and 'Continue Shoping'. The bacakground is partially obscured by a white overlay.

This too!

Product page with a minicart dropping down from the header, which shows our just added product, a total price, and a button to proceed to checkout.

Even this a dialog

Product page with a cart drawer on the right, with an overlay obscuring the product content.

Focus Management

  • Move focus to the dialog
  • If modal, trap focus, but also allow focus to move to browser UI elements
  • Return focus to the element that opened the dialog


  • Don't forget keyboard shortcuts! Hitting the escape key should close the dialog.
  • Screen reader users shouldn't be able to escape the modal through other keyboard means. In the future, aria-modal="true" should have more support, but inert works for now
  • Don't dismiss dialogs automatically

Which element to use?

  • <dialog> is just about here!
  • <div> with role="dialog"

Label ALL the things!

  • Label your dialog - consider aria-labelledby
  • If your dialog has repetitive interactive elements (eg. multiple 'Increase Quantity') buttons, make sure they have unique names


  • No clear winner amongst patterns
  • Testing individual components is important, but testing whole flows is essential
  • toasts and dialogs are NOT the same. Accessibility errors come about from treating different components interchangably.