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.

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.

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.