Accessible checkout: testing the purchase journey step by step

Photograph: a small wire shopping basket on a light grey surface, with a pink glint of light.

In short: An accessible checkout can be completed from basket to order confirmation with a keyboard alone and with a screen reader. Every field has a visible label, errors are named and explained, basket changes are announced, and the order button says plainly that you are about to pay. Test every step with real orders – an automated check reaches only part of it.

The purchase journey is the part of a shop that counts most under the European Accessibility Act, and under Germany's BFSG. This is where the service the law is about is provided: concluding a contract. And this is where every barrier costs revenue directly, because anybody who cannot reach the order button buys elsewhere. This guide walks the journey step by step and ends with a test protocol. What else the law asks of shops is in our guide for online shops.

Why the checkout decides revenue

On a product page a customer can work round a barrier: miss the image but read the text; fail with the filter but use the search. In the checkout there are no detours. Every step has to succeed, or there is no order. That is why the purchase journey is the first one to test, and the one to test again after every update.

There is a particular twist: checkouts are often assembled from parts by different vendors. The theme supplies the basket, a plugin the address validation, the payment provider the card fields, another vendor the express buttons. Any of them can break the journey.

Basket: quantities, vouchers, status messages

The basket is a small form with many states. Check that:

  • Quantity fields have a name that includes the product – not "Quantity" five times over. Plus and minus buttons are real buttons with names such as "Increase quantity of Alpina hiking boot".
  • Remove is a button with a name, not just a bin icon.
  • Changes are announced. If the total or shipping cost updates without a reload after a change, a screen reader has to learn about it. A status message does that (4.1.3 Status Messages).
  • Voucher fields report success and failure in text, not only with a green or red border.
<p role="status" class="visually-hidden" id="cart-status"></p>
// after the basket has been updated successfully
document.getElementById('cart-status').textContent =
  'Basket updated. Subtotal €84.90.'

The empty container has to be in the document when the page loads; only then is a later change of its text announced reliably.

Address and guest checkout

Address forms are where most checkouts fail. The basics – visible labels, error messages, required fields – are in our guide to accessible forms. The checkout adds three points:

  • Autocomplete. Name, email, street, postcode, town, country and phone need the right autocomplete values so that browsers and assistive technology can fill them in (1.3.5 Identify Input Purpose).
  • No double entry. The billing address defaults to the delivery address, and anybody signed in to their account does not type their address again (3.3.7 Redundant Entry).
  • Guest checkout without hurdles. Compulsory registration with password rules and a captcha is the first wall for many people. Offer guest checkout on equal terms, and where there is a sign-in, it must work without a memory test or a puzzle (3.3.8 Accessible Authentication).
<label for="postal">Postcode</label>
<input id="postal" name="postal" autocomplete="shipping postal-code">

Delivery and payment choice

Delivery and payment options are almost always choice groups – and almost always designed as tiles. Underneath the design there should be native radio buttons in a group with a legend:

<fieldset>
  <legend>Delivery</legend>
  <input type="radio" id="ship-std" name="shipping" value="standard" checked>
  <label for="ship-std">Standard, 2–4 working days, €4.90</label>
  <input type="radio" id="ship-exp" name="shipping" value="express">
  <label for="ship-exp">Express, next working day, €9.90</label>
</fieldset>

The label includes price and delivery time, not just a logo. Arrow keys move within the group and Tab moves on to the next group – which is what keyboard users expect. If the choice changes the total, that belongs in a status message. And the choice must not jump to the next page on its own: a change of context on mere selection conflicts with 3.2.2 On Input.

Payment iframes and express buttons

Card fields usually come from the payment provider, in an iframe. The provider designs what is inside; you are responsible for how it is embedded:

  • The iframe has a title that says what it contains, such as "Card details". The frame-title rule checks this.
  • The tab order leads into the iframe and out again without focus getting lost.
  • The provider's error messages appear where the field is and are announced. If they are not, ask the provider for its accessibility documentation.

Express buttons such as PayPal, Apple Pay or Google Pay also come from outside. They must have an accessible name, be reachable by keyboard and must not push the actual checkout aside. Check that focus lands back in the checkout after an express flow is cancelled.

Errors and the order button

Just before the end comes the page that matters most, legally and practically. Three requirements meet here:

  • Check before it is binding. On pages that trigger a payment, users must be able to review and correct their details before submitting – on a summary page, for example (3.3.4 Error Prevention).
  • Report errors clearly. If something is missing – agreement to the terms, a required field – the error is named in text and focus leads to it.
  • The order button. In Germany, section 312j(3) of the Civil Code requires the button that submits an order to be legibly labelled "zahlungspflichtig bestellen" ("order with obligation to pay") or with an equally unambiguous wording [2]; for English-language shops, "Buy now" or "Order and pay" follow the same idea. For accessibility, the accessible name must contain the visible text. An aria-label="Continue" on a button reading "Order and pay" breaks 2.5.3 Label in Name – and voice control can no longer find the button.
<button type="submit" class="btn-order">Order and pay</button>

After submitting, the confirmation page gets a clear title and a heading that states the success. Focus lands on that heading or at the top of the page, not somewhere in the footer.

Time limits and expired sessions

Many checkouts have time limits nobody introduced on purpose: a session that expires after 15 minutes, a reserved basket with a countdown, a payment page that has to be reloaded after a while. People shopping with a screen reader, voice control or switch access often need much longer for the same journey. 2.2.1 Timing Adjustable requires such limits to be switched off, adjusted or extended – with a warning shortly before expiry and a "More time" button, for example. And if a session does expire, the details already entered must not be lost.

A test protocol to take away

Walk the journey with a real test order, once with the keyboard only and once with a screen reader – NVDA on Windows or VoiceOver on a Mac. Note for each step what works and what does not.

  1. Add a product to the basket, keyboard only. Is success announced, and where is focus afterwards?
  2. In the basket, change a quantity and remove an item. Do all buttons have names, and are new totals announced?
  3. Enter an invalid voucher code. Is the error stated in text?
  4. Go to checkout and order as a guest. Is guest checkout as easy to reach as signing in?
  5. Enter the address and leave one required field empty. Are errors named, and does focus move to the error or an error summary?
  6. Choose delivery and payment with the arrow keys. Are price and delivery time part of the label, and does the page stay put?
  7. Enter card details in the payment iframe. Does focus get in and out, and do the fields have names?
  8. On the summary page, review the details and change one of them. Is that possible without re-entering everything?
  9. Find the order button. Does it say it commits you to pay, is its focus visible, and does the screen reader announce the same text?
  10. Read the confirmation page. Does the heading say the order has been received?

Repeat the protocol after every theme, plugin or payment provider update. For individual shop systems, our guides to Shopware, Shopify and WordPress with WooCommerce help.

What Reviseberg checks here – and what it does not

Reviseberg crawls the publicly reachable pages of your shop and runs the axe-core rules on each: missing labels, buttons without names, invalid autocomplete values, iframes without titles, insufficient contrast. The keyboard agent presses Tab, Shift+Tab and Escape on the page you name as its start page and shows step by step where focus goes, whether it is visible and whether anything stays unreachable – give it your basket page or checkout entry page, for example.

On a crawl from your account, Reviseberg also fills in the forms on one page per template with test data – never real payment details – and sends them with every write refused, so your server hears nothing. It reports, for example, fields whose purpose no autocomplete names, labels that disappear while typing, errors not named in text or not announced, and pasting blocked in sign-in fields. What Reviseberg does not do: it puts nothing in the basket for real and submits no order. What your server answers when a form is sent – its error messages, the next step behind a full basket – it sees only on a staging copy whose Admin allowed form submissions, and the payment itself never. Those steps are yours to test by hand with the protocol above.

Frequently asked questions

Does the whole checkout have to be accessible, including the payment provider's part?

The journey as a whole must be usable. The provider is primarily responsible for what is inside its payment iframe; how you embed it, and whether customers can complete the journey, is down to you. Ask your provider for its audit report.

How do I test the checkout without placing real orders?

Most shop systems and payment providers have a test or sandbox mode. Use it for the protocol, or set up a payment method such as bank transfer that you cancel afterwards.

How must the order button be labelled?

For shops selling to consumers in Germany, section 312j(3) of the Civil Code requires "zahlungspflichtig bestellen" or an equally unambiguous wording. For accessibility, the accessible name must contain that visible text; a different aria-label is a failure.

Is an automated check enough for the checkout?

No. Automated rules find missing labels and names, but not whether an error message is understandable or whether the journey continues after submitting. That takes a test order by hand.

How often should I test the checkout?

After every change to the theme, plugins or payment methods, and regularly beyond that. Checkouts change often without anybody touching the templates – when a provider updates its widget, for example.

Sources

  1. W3C, Web Content Accessibility Guidelines (WCAG) 2.2 – https://www.w3.org/TR/WCAG22/
  2. German Civil Code (BGB), section 312j, special duties in e-commerce towards consumers – https://www.gesetze-im-internet.de/bgb/__312j.html
  3. WHATWG HTML Standard, Autofill (autocomplete values) – https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill
  4. W3C, Understanding WCAG 2.2: Status Messages – https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html

See what a scan finds on your site

One page in about thirty seconds, no email needed. The full report covers up to 100 pages and a keyboard journey.