Quantity steppers appear on almost every e-commerce site. They look simple: a minus button, a number, a plus button. But they’re deceptively tricky to implement with accessibility best practices. I recently looked at two real-world examples, Hannaford and Walmart, and found that both get different parts right and different parts wrong.

Hannaford

Hannaford’s implementation has some solid foundations. Proper <button> elements, aria-labels on both buttons, an editable input field so users can type a quantity directly, and icons correctly hidden from screen readers with aria-hidden="true".

But two things are missing. The button labels (“Decrease quantity” / “Increase quantity”) have no product context. A screen reader user navigating a page with multiple steppers hears “Decrease quantity” with no indication of which product they’re adjusting. And there’s no live region, so when a user clicks the buttons, screen readers don’t announce the updated quantity at all.

Hannaford search results for stonyfield yogurt showing the first product with an active quantity stepper displaying value 1 in an editable input field, flanked by minus and plus buttons. Browser dev tools panel below shows the quantity stepper markup including a decrement button with aria-label Decrease quantity, an input element with aria-label Quantity in cart and type text, and an increment button with aria-label Increase quantity.

Walmart

Walmart’s implementation gets the announcements right. Their button aria-labels include both the product name and current quantity: “Decrease quantity Stonyfield Organic Vanilla Whole Milk Probiotic Yogurt, 32 oz Container, Current Quantity 1.” There’s no ambiguity about which product or what the current value is.

They also include a live region to announce changes. But it uses aria-live="assertive" which interrupts whatever the screen reader is saying immediately. For a non-urgent quantity change, aria-live="polite" is the better choice.

The bigger gap: there’s no input field. The quantity is a non-editable <span>. Users can only increment or decrement by one at a time, with no way to enter a quantity directly.

Walmart search results for stonyfield yogurt showing the first product with an active quantity stepper displaying value 1, flanked by circular blue minus and plus buttons. Browser dev tools panel below shows the quantity stepper markup including an aria-live assertive span, two button elements with detailed aria-labels including product name and current quantity, and a span element with data-testid quantity-label displaying the value 1.

What the ideal implementation looks like:

This sample code includes Hannaford’s editable input, Walmart’s product-context aria-labels, and a polite live region:

<div aria-live="polite" aria-atomic="true" class="sr-only">Quantity updated to 3</div>
<button type="button" aria-label="Decrease quantity, Stonyfield Organic Yogurt, current quantity 2">
  <svg aria-hidden="true"><!-- minus icon --></svg>
</button>
<label for="qty-49231864" class="sr-only">Quantity, Stonyfield Organic Yogurt</label>
<input type="number" id="qty-49231864" min="0" max="99" value="2">
<button type="button" aria-label="Increase quantity, Stonyfield Organic Yogurt, current quantity 2">
  <svg aria-hidden="true"><!-- plus icon --></svg>
</button>

A few things to note:

  • The live region announces the updated value after each change.
  • The input has a visually hidden label that includes the product name.
  • The button aria-labels update dynamically to reflect the current quantity so screen reader users always know where they are.

Quantity steppers are a good reminder that accessible components require attention to multiple details simultaneously. Getting the buttons right doesn’t mean the live region is right. Having an input doesn’t mean the announcements work.

Don’t Miss Out

Get practical accessibility tips in your inbox every week.

Matt Litzinger headshot

Matt Litzinger

Matt is a web developer who builds tools that help organizations better engage with customers and improve website accessibility.