Commerce · Pattern

Repeat the card, not its mistakes.

A product grid combines list semantics, concise tab order, unique buttons, asynchronous states, and one complete cart announcement.

The pattern

The product grid and status pattern

Each card owns its controls. The collection owns its list. One status region owns cart feedback.

Keyboard-testable shop

Three products, six useful stops.

Cart: 0 items

Boot linkBoot addPack linkPack addShell linkShell add

Composition

Keep responsibility local.

A shared live region should announce a complete result such as product plus quantity. Do not place a live region in every card or move focus to the cart count.

Collection and cards

List structure surrounds independent product articles.

<ul class="products">
  <li><article>…title link…add button…</article></li>
</ul>

One persistent status

The full message updates without receiving focus.

<p role="status" aria-atomic="true">Cart: 0 items</p>

status.textContent = `Cart: ${count} items. ${product} added.`;

Quick test

Multiply your checks too.

  1. Confirm the collection is announced as a list with the expected number of items.
  2. Confirm each product title is a heading link and each image is absent from tab order.
  3. Confirm every Add to cart name includes its product.
  4. Add each product and listen for product name plus updated cart quantity.
  5. Confirm focus stays on the button during and after its request.
  6. Resize the grid and confirm DOM, reading, and focus order remain aligned.