← Back
[W] Writing

An address form for 16 countries

An address form is one of the first things you'd call simple. Street, city, state, ZIP.

Most address forms are a US address form with a country dropdown on top. A shopper in London has no state to pick. A shopper in Berlin writes the postal code before the city. A shopper in Tokyo starts from the other end entirely.

When I built the Address Form block for HextaUI, it had to handle 16 countries. Change the country below.

A cut-down version with five countries and a fallback. Type in a postal code, then change country and watch what carries over.

The country decides everything

The country isn't one more field. It decides which fields exist, what they're called, which are required and what order they go in.

Country After the street Region Postal code
United States City, State, ZIP Required 12345
United Kingdom Town or city, Postcode None SW1A 1AA
Germany Postal code, City None 5 digits
Japan Postal code, Prefecture, City Required 123-4567
Canada City, Province, Postal code Required K1A 0B1

So the form never mentions a country by name. It only renders rows from data.

const JP = {
  rows: [["postalCode", "region"], ["city"]],
  localityFirst: true,
  required: ["postalCode", "region", "city"],
  labels: {
    city: "City, ward or town",
    region: "Prefecture",
  },
  postal: { pattern: /^\d{3}-?\d{4}$/, example: "100-0001" },
};

That's a shortened version of the real entry. localityFirst is the big one for Japan, because the street comes after the area. Each entry also holds a phone format, how to print the address, and other names for the country, so a search for 日本 finds Japan.

Details that only show up in real use

Autofill does most of the work. Browsers can fill the whole form in one tap, if every input has the right token. shipping address-level2 means city. address-level1 means state or region. This is the highest-value part of the whole form, and you never see it.

Don't throw away what they typed. People choose a country after typing, or change it by mistake. Fields that exist in both countries should keep their values.

Validate gently. Check the postal code format for countries you know, but don't invent rules for the rest. A wrong validation rule is worse than none, because it stops a real person from giving you a real address and they have no way around it.

Have a plain fallback. I can't cover every country by hand, and I shouldn't pretend to. Everywhere else gets two address lines, city, region and postal code, with none strictly validated.

The 16 countries with their own format
  • US
  • CA
  • GB
  • IE
  • DE
  • FR
  • NL
  • ES
  • IT
  • JP
  • IN
  • AU
  • NZ
  • SG
  • BR
  • MX
Everyone else gets the fallback, and that's a deliberate decision.

This one is personal for me

If you live outside the US, you've probably met a form that was sure you had a ZIP code and a state from a fixed American list. The form is telling you, politely, that nobody thought of you.

That's what makes a form like this worth the work. It's the longest form in most stores, and it comes right before someone pays you. A person who has to fight it might just leave.

If you're building one, read Google's address metadata from libaddressinput before you write any rules yourself. Most of this is already written down.

Next