Address form
Category: Forms · Tags: address, form, autocomplete, fieldset, checkout
How to use it
Use for a single shipping or billing address in checkout or account settings. Do not use it to search for a location; use a search field with suggestions instead. Give every id a unique prefix if a page shows two addresses, add the countries you actually ship to, and keep the labels in sync with the script's hint table.
Accessibility
A <fieldset> with a <legend> groups the fields, every input and the country <select> has its own <label for>, and each carries the matching autocomplete token (name, country, address-line1, address-line2, address-level2, address-level1, postal-code) so browsers and password managers can fill it. The postcode hint is linked through aria-describedby, and its wording and the field label follow the chosen country. Labels and input text are #0f172a on white (17.85:1), the hint and the "(optional)" marker #475569 on white (7.58:1), and every control shows a 2px #1d4ed8 focus outline.
Source (copy-ready)
<fieldset class="dcl-address">
<legend class="dcl-address__legend">Shipping address</legend>
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-country">Country or region</label>
<select class="dcl-address__control" id="dcl-address-country" name="country" autocomplete="country">
<option value="US">United States</option>
<option value="GB">United Kingdom</option>
<option value="CA">Canada</option>
<option value="DE">Germany</option>
<option value="JP">Japan</option>
<option value="AU">Australia</option>
</select>
</div>
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-name">Full name</label>
<input class="dcl-address__control" type="text" id="dcl-address-name" name="name" autocomplete="name" required>
</div>
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-line1">Street address</label>
<input class="dcl-address__control" type="text" id="dcl-address-line1" name="address-line1" autocomplete="address-line1" required>
</div>
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-line2">Apartment, suite or unit <span class="dcl-address__optional">(optional)</span></label>
<input class="dcl-address__control" type="text" id="dcl-address-line2" name="address-line2" autocomplete="address-line2">
</div>
<div class="dcl-address__row">
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-city">City or town</label>
<input class="dcl-address__control" type="text" id="dcl-address-city" name="address-level2" autocomplete="address-level2" required>
</div>
<div class="dcl-address__field">
<label class="dcl-address__label" for="dcl-address-region">State, province or region</label>
<input class="dcl-address__control" type="text" id="dcl-address-region" name="address-level1" autocomplete="address-level1">
</div>
<div class="dcl-address__field">
<label class="dcl-address__label dcl-address__postcode-label" for="dcl-address-postcode">ZIP code</label>
<input class="dcl-address__control" type="text" id="dcl-address-postcode" name="postal-code" autocomplete="postal-code" aria-describedby="dcl-address-postcode-hint" required>
<p class="dcl-address__hint" id="dcl-address-postcode-hint">5 digits, for example 94110</p>
</div>
</div>
</fieldset>
<style>
.dcl-address { display: flex; flex-direction: column; gap: 0.9rem; max-width: 36rem; min-width: 0; margin: 0; padding: 1rem; border: 1px solid #cbd5e1; border-radius: 0.5rem; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-address__legend { padding: 0 0.35rem; font-weight: 700; color: #0f172a; background-color: #ffffff; }
.dcl-address__row { display: flex; flex-wrap: wrap; gap: 0.9rem; }
.dcl-address__field { display: flex; flex-direction: column; gap: 0.3rem; flex: 1 1 9rem; min-width: 0; }
.dcl-address__label { font-weight: 600; color: #0f172a; background-color: #ffffff; }
.dcl-address__optional { font-weight: 400; color: #475569; background-color: #ffffff; }
.dcl-address__control { box-sizing: border-box; width: 100%; max-width: 100%; padding: 0.5rem 0.65rem; border: 1px solid #64748b; border-radius: 6px; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-address__control:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
.dcl-address__hint { margin: 0; font-size: 0.85rem; color: #475569; background-color: #ffffff; }
</style>
<script>
(function () {
var formats = {
US: ["ZIP code", "5 digits, for example 94110"],
GB: ["Postcode", "For example SW1A 1AA"],
CA: ["Postal code", "For example K1A 0B1"],
DE: ["Postcode", "5 digits, for example 10115"],
JP: ["Postal code", "7 digits, for example 100-0001"],
AU: ["Postcode", "4 digits, for example 2000"]
};
document.querySelectorAll(".dcl-address").forEach(function (root) {
if (root.dataset.dclBound) { return; }
root.dataset.dclBound = "true";
var country = root.querySelector("select[autocomplete=\"country\"]");
var label = root.querySelector(".dcl-address__postcode-label");
var hint = root.querySelector(".dcl-address__hint");
if (!country) { return; }
function update() {
var format = formats[country.value];
if (!format) { return; }
if (label) { label.textContent = format[0]; }
if (hint) { hint.textContent = format[1]; }
}
country.addEventListener("change", update);
update();
});
})();
</script>
Was this useful? Send feedback.