Addresses
Follow this pattern whenever you need to ask users for an address.
When to use this pattern
Only ask for an address if you genuinely need it for your service. For example, to:
- send correspondence
- verify someone's identity
- determine eligibility based on location
How it works
Use multiple text inputs rather than a single textarea. This makes it easier for users to enter their address correctly and helps with data quality.
Standard address form
<fieldset class="form-group">
<legend class="form-label form-label-lg">What is your address?</legend>
<!-- Row 1: Address 1 (wider) | Address 2 (narrower) -->
<div class="form-row form-row-2-1">
<div class="form-group">
<label class="form-label" for="address-line-1">
Address line 1 <span class="form-required">*</span>
</label>
<input class="form-input" id="address-line-1" type="text" autocomplete="address-line1">
</div>
<div class="form-group">
<label class="form-label" for="address-line-2">Address line 2</label>
<input class="form-input" id="address-line-2" type="text" autocomplete="address-line2">
</div>
</div>
<!-- Row 2: City / Town | Province -->
<div class="form-row form-row-1-1">
<div class="form-group">
<label class="form-label" for="address-town">
City / Town <span class="form-required">*</span>
</label>
<input class="form-input" id="address-town" type="text" autocomplete="address-level2">
</div>
<div class="form-group">
<label class="form-label" for="address-province">Province</label>
<input class="form-input" id="address-province" type="text" autocomplete="address-level1">
</div>
</div>
<!-- Row 3: Postal Code (narrower) | Country (wider) -->
<div class="form-row form-row-1-2">
<div class="form-group">
<label class="form-label" for="address-postcode">Postal code</label>
<input class="form-input" id="address-postcode" type="text" autocomplete="postal-code">
</div>
<div class="form-group">
<label class="form-label" for="address-country">
Country <span class="form-required">*</span>
</label>
<select class="form-select" id="address-country" autocomplete="country-name">
<option value="">Select a country</option>
<!-- Countries loaded from API -->
</select>
</div>
</div>
</fieldset>Form row classes
Use these CSS classes for different column layouts:
| Class | Description |
|---|---|
.form-row | Base class - equal columns on desktop, stacked on mobile |
.form-row-2-1 | 2:1 ratio (wider left, narrower right) |
.form-row-1-2 | 1:2 ratio (narrower left, wider right) |
.form-row-1-1 | Equal 50/50 split |
.form-row-3 | Three equal columns |
Responsive behaviour: On screens below 640px, all form rows automatically stack vertically. Fields display full-width in a single column, maintaining the same field order as on desktop.
Country selector
The country selector loads countries from the Kaharagia API. Countries are sorted alphabetically by name.
API endpoint: Countries are fetched from citadel.kaharagia.org/api/countries and displayed by their name field.
Error handling
If the countries API fails to load, provide a fallback experience:
- Show a text input instead of the dropdown, allowing users to type their country
- Display a subtle warning that the country list could not be loaded
- Retry the API request when the user focuses the field
- Never block form submission due to a failed country lookup
Kaharagian addresses
Kaharagian addresses typically follow this format:
- Street address
- Suburb or locality
- Province
- Postal code
- KAHARAGIA
Error messages
Use these error messages for address validation:
- If address line 1 is empty
- "Enter the first line of your address"
- If city / town is empty
- "Enter your city or town"
- If province is empty
- "Enter your province"
- If postal code is empty
- "Enter your postal code"
- If postal code format is invalid
- "Enter a valid postal code"
- If country is not selected
- "Select a country"
Accessibility
- Use the
autocompleteattribute to help users fill in address fields - Group related fields in a
<fieldset>with a<legend> - Mark optional fields clearly
- All form fields should have visible labels
- Error messages should be linked to their fields using
aria-describedby