Most shoppers pay with a card registered to the same address they're shipping to. Making them type the exact same seven fields twice is pure friction with no payoff. A default-checked "Same as shipping" toggle collapses the billing section to a single checkbox for the common case while preserving separate-address entry for the minority that needs it. Missing this pattern adds roughly thirty seconds of typing and a fresh set of typo opportunities on every checkout.
Low because the defect only affects shoppers with matching addresses, but it adds friction on the majority path.
Add a default-checked "Same as shipping" toggle in src/components/CheckoutAddresses.tsx. When checked, copy shipping values into billing state and hide the billing fields. When unchecked, render the full billing form.
const [sameAsShipping, setSameAsShipping] = useState(true)
<input type="checkbox" checked={sameAsShipping} onChange={e => { setSameAsShipping(e.target.checked); if (e.target.checked) setBillingAddress(shippingAddress) }} />
{!sameAsShipping && <BillingForm value={billingAddress} onChange={setBillingAddress} />}
ID: ecommerce-cart-ux.address-forms.billing-auto-match
Severity: low
What to look for: Search checkout components for a "Same as shipping" or "Use shipping address for billing" checkbox/toggle. Count the billing address fields and check if they are conditionally rendered (hidden when the toggle is checked). Quote the toggle state variable and the conditional rendering logic. Verify the toggle defaults to checked (same as shipping) to minimize friction.
Pass criteria: A "Same as shipping" checkbox or toggle is present, is checked by default, and hides at least 4 billing address fields when active. Users can uncheck to enter a separate billing address. Report: "Billing-match toggle found in [component], defaults to checked, hides X billing fields."
Fail criteria: Users must manually enter billing address in full even if it matches shipping, or no copy/match mechanism exists.
Skip (N/A) when: Only shipping address is collected (payment provider handles billing separately, or no separate billing address form exists).
Detail on fail: Example: "Billing address form at src/components/BillingForm.tsx always renders 5 fields. No 'Same as shipping' toggle found. Users must re-enter full address even when billing matches shipping."
Cross-reference: For address field count minimization, see the minimal-fields check above. For shipping address autocomplete, see the autocomplete check above.
Remediation: Add a billing-match toggle in your checkout address section at src/components/CheckoutAddresses.tsx:
// src/components/CheckoutAddresses.tsx
function CheckoutAddresses() {
const [sameAsShipping, setSameAsShipping] = useState(true)
const [shippingAddress, setShippingAddress] = useState({})
const [billingAddress, setBillingAddress] = useState({})
return (
<>
<ShippingForm value={shippingAddress} onChange={setShippingAddress} />
<label>
<input
type="checkbox"
checked={sameAsShipping}
onChange={(e) => {
setSameAsShipping(e.target.checked)
if (e.target.checked) setBillingAddress(shippingAddress)
}}
/>
Billing address same as shipping
</label>
{!sameAsShipping && (
<BillingForm value={billingAddress} onChange={setBillingAddress} />
)}
</>
)
}