# Checkout forms that ask for the same address twice

Source: https://easeweb.dev/learn/redundant-entry
Topics: Forms > People do not enter the same thing twice (WCAG 3.3.7)
The fix: Either add a "Billing address is the same as delivery address" checkbox, ticked by default, that hides the billing fields, or fill the billing fields in with the delivery address so people change only what differs. Showing the delivery address on the same page to copy also passes 3.3.7, but leaves people copying it line by line.
Test with: keyboard, screen reader, touch
References: https://www.w3.org/WAI/WCAG22/Understanding/redundant-entry.html https://www.w3.org/WAI/WCAG22/Techniques/general/G221 https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A shop's checkout has two steps. The first, Delivery, asks for a full name, a street address and a postcode. The person fills them in and presses Continue to payment. The second step asks for the card, then for a billing address: full name, street address and postcode, the same three fields, all empty. For most people the billing address is the delivery address, so they type it again, line by line, from memory or after going back a step to look.

The same thing happens across many processes:

- A guest checkout asks for an email at the start, then asks for it again on the last step to "create an account".
- A booking takes the names of everyone travelling, then asks for the lead traveller's name again on the payment step.
- A "Confirm email" field refuses paste, so the address has to be typed twice.
- A form empties itself when a card is declined, or when the person goes back a step to fix something.

## Why it fails

Success criterion 3.3.7, Redundant Entry, is level A and new in WCAG 2.2. When a process asks again for information the person entered or was given earlier in it, that information must be either filled in already or available to select. The billing fields are neither.

The browser's autofill doesn't count. It depends on what the person's browser happens to have saved, so the site itself has to offer the earlier answer. "Available to select" is broad: a checkbox that reuses it, a choice from a list, or the value shown on the same page so it can be copied. Three exceptions apply: re-entry that is essential, as in a memory game; re-entry for security, such as confirming a new password that isn't shown; and an earlier value that is no longer valid, such as an expired card.

The criterion covers one process, not every visit. It doesn't ask a site to remember last week's address, but a process can cross pages and even domains, as a hosted payment page does.

## Who is affected

On a phone the cost doubles: the on-screen keyboard covers half the form, and the delivery step is no longer on screen to copy from.

## What automation and AI miss

Each page is fine on its own. Every field has a label and an autocomplete token, so axe and other scanners pass both steps. The repeat only shows to someone who goes from the first step to the second. EaseWeb's audit reports a field that asks again on the same page and refuses paste, and flags forms that ask for a billing address for a person to check, but it can't follow a checkout through. A code assistant asked to "add a billing address" adds empty fields, and asked to fix 3.3.7 it often adds autocomplete tokens, which help autofill but don't meet this criterion.

## Before: the billing address asked again, empty

```html
<!-- Step 2 of 2: Payment -->
<fieldset>
  <legend>Billing address</legend>
  <label for="bill-name">Full name</label>
  <input id="bill-name" name="bill-name" autocomplete="billing name">
  <label for="bill-street">Street address</label>
  <input id="bill-street" name="bill-street" autocomplete="billing street-address">
  <label for="bill-postcode">Postcode</label>
  <input id="bill-postcode" name="bill-postcode" autocomplete="billing postal-code">
</fieldset>
```

The fields are labelled and declare their purpose, so they pass 1.3.5. But the delivery address from step 1 is nowhere on this page: not in the fields, not as a choice, not even as text to copy.

## After: a same-as-delivery checkbox, ticked by default

```html
<label>
  <input type="checkbox" id="billing-same" name="billing-same" checked
    aria-describedby="delivery-address">
  Billing address is the same as delivery address
</label>
<p id="delivery-address">Sam Rivera, 12 Elm Street, AB1 2CD</p>
<fieldset id="billing" hidden disabled>
  <legend>Billing address</legend>
  <label for="bill-name">Full name</label>
  <input id="bill-name" name="bill-name" autocomplete="billing name">
  <label for="bill-street">Street address</label>
  <input id="bill-street" name="bill-street" autocomplete="billing street-address">
  <label for="bill-postcode">Postcode</label>
  <input id="bill-postcode" name="bill-postcode" autocomplete="billing postal-code">
</fieldset>
```

```js
const same = document.getElementById('billing-same');
const billing = document.getElementById('billing');
same.addEventListener('change', () => {
  billing.hidden = same.checked;
  billing.disabled = same.checked;
});
```

People whose billing address matches have nothing to type: the box is already ticked, and the address it reuses is shown beside it and read with it. People whose address differs untick it and get empty fields, which is new information, so 3.3.7 doesn't apply to it. While the box is ticked the fieldset is hidden and disabled, so its fields are skipped by Tab, by screen readers and by the browser's validation, and none of them is sent. On the server, a ticked box means the delivery address.

## After: the billing fields filled in from the delivery step

```html
<fieldset>
  <legend>Billing address</legend>
  <p id="bill-hint">We've filled in your delivery address. Change anything that's different.</p>
  <label for="bill-name">Full name</label>
  <input id="bill-name" name="bill-name" autocomplete="billing name"
    value="Sam Rivera" aria-describedby="bill-hint">
  <label for="bill-street">Street address</label>
  <input id="bill-street" name="bill-street" autocomplete="billing street-address"
    value="12 Elm Street">
  <label for="bill-postcode">Postcode</label>
  <input id="bill-postcode" name="bill-postcode" autocomplete="billing postal-code"
    value="AB1 2CD">
</fieldset>
```

The server writes the delivery answers into the billing fields when it renders step 2, escaped as any value put into HTML must be. The fields are auto-populated, so people only change what differs. The hint, read with the first field, says where the values came from. Everyone still reads a second copy of their address to check it, and someone whose billing address is different has to clear each field before typing.

## After: the delivery address shown on the page to copy

```html
<p>Delivering to: Sam Rivera, 12 Elm Street, AB1 2CD</p>
<fieldset>
  <legend>Billing address</legend>
  <label for="bill-name">Full name</label>
  <input id="bill-name" name="bill-name" autocomplete="billing name">
  <label for="bill-street">Street address</label>
  <input id="bill-street" name="bill-street" autocomplete="billing street-address">
  <label for="bill-postcode">Postcode</label>
  <input id="bill-postcode" name="bill-postcode" autocomplete="billing postal-code">
</fieldset>
```

This is the smallest change, and it passes 3.3.7: the Understanding document counts text on the same page that can be selected and copied into the field as available to select. It holds only while the address is on this page, in real text, selectable (no `user-select: none`) and the fields accept paste. It is not enough on its own. People still copy and paste three lines one at a time, and that is slow and easy to get wrong with a switch, voice input, a screen reader or a tremor.

## Which option to use

All three pass 3.3.7. Use the ticked checkbox: people whose addresses match, who are usually most, have nothing to type or check, and people whose addresses differ get empty fields rather than a copy to clear field by field. Fill the fields in when the design can't take another control, or when the two addresses tend to differ in only one line, such as a company name. Showing the address to copy is a first step for a payment form whose fields you can't change but whose page you can; replace it with one of the other two when you can.

## Implementation decisions

Keep a process's answers on the server, in the checkout session, not only in the page's script. Then a reload, the Back button or a failed submission doesn't lose them, and every later step can read from the same record instead of asking. After a declined card, keep everything but the card's security code, which may be asked again for security.

A "Confirm email" field asks for the same address twice. It passes 3.3.7 only while paste works, since the first answer is on the same page to copy. It is better to remove it, and to show the address back on the review step with a link to change it. A field that cancels paste fails, and EaseWeb's audit reports one that asks again and refuses an empty test paste. Confirming a new password is allowed under the security exception, but blocking paste there fails 3.3.8; offer a "Show password" button instead of the second field where you can.

When a process has more than one earlier answer to offer, such as several recipients' addresses, offer them as radio buttons with "A different address" as the last choice. That is available to select, as a checkbox is.

Keep the autocomplete tokens on every field, with the `billing` and `shipping` prefixes. They don't meet 3.3.7, but they let autofill fill the fields when someone does give a different address; see [form fields that block or break autofill](/learn/autocomplete).

When the checkbox hides the fields, disable them too. A hidden `required` field that isn't disabled still blocks the submission, and the browser can't move focus to it to say why.

## Verify the fix

1. Go through the process from its first step to its last, and note every value it asks for more than once, including values it gave you, such as an order reference.
2. At each repeat, confirm the earlier value is filled in, reused by a ticked checkbox, offered as a choice, or shown on the same page to copy.
3. Give a different billing address, by unticking the box, changing the filled-in fields or typing it in, and confirm the order records that address and not the delivery one.
4. Copy a value from the page and paste it into any field that asks for it again, with the keyboard and with the context menu, and confirm it goes in.
5. Go back a step, then come forward again, and submit once with an error. Confirm everything you entered is still there.
6. With a screen reader, confirm the ticked checkbox and the address it reuses, or the filled-in values, are read on the billing step before the Pay button.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the checkout's steps or its shared form components change.

## Limits

This is a starting pattern, not a guarantee for every process. The example is a two-step checkout; sign-up flows, bookings and applications need the same walk-through, step by step. Payment fields inside a provider's frame are the provider's to fix, but the page around them is yours. The criterion doesn't require remembering details between visits, and saved addresses are a separate feature with their own privacy questions. Test the complete process with the people and tools your users rely on.
