Skip to content

Components · Location

LocationFields

Country, region, city and postal code as one composite, with the data source injected.

@rookcom/monarch-reactComponent

Controlled address

Billing address
{
  "country": "CA",
  "region": "CA-ON",
  "regionName": "Ontario",
  "city": "Toronto",
  "cityId": "ca-tor",
  "postalCode": ""
}

Usage examples

Subset and failure

Purpose

The address part every form re-implements: a searchable country, a region list that uses each country’s own word for it, a server-searched city that can also be typed freely, and a postal code. The lists come from an adapter the product provides.

Use when

  • Any form that takes a postal or business address.
  • The product has a geographic data source and wants stored codes (country, region, city ids) beside the text.

Avoid when

  • Only a country is needed: a single Combobox of countries is simpler.
  • A street-level autocomplete from a maps provider is wanted; that is a different, provider-specific control.

Design principles

  • No data, no network: Monarch ships no geographic lists and makes no requests. adapter is the only source.
  • Codes and text together: the value stores each code beside its label, so the server can verify and canonicalise it.
  • Local words: the region label comes from the adapter ("Province", "Emirate"), never a hard-coded "State".
  • Never a dead end: a city missing from the data can be typed, a country without regions gets a free-text field, and a failed list offers Try again.

API reference

import { LocationFields } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
LocationFieldscomponentclient.mn-location-fields

Renders a <fieldset class="mn-location-fields"> with a Field per part. The ref goes to the fieldset.

LocationAdapter has countries(signal), optional regions(country, signal) and optional cities({ country, region, query }, signal). Omit regions or cities for free-text fields.

Generated from the TypeScript declarations of packages/react/src/components/geo/location-fields.

Properties

onValueChange(value, changed) receives the whole LocationValue and which field changed. Changing the country resets every other part; changing the region resets the city.

LocationFields

Country, region, city and postal code as one composite. Lists come from an injected adapter, so the product owns the data and the requests. Picking a country loads its regions under the country's own word; cities are searched as the user types, can be typed freely, and fill in their region.

PropTypeDescription
adapter requiredLocationAdapterThe data source. Required.
allowCustomCitybooleanOffer the typed text as a city when it is not in the list. Default true.
childrenReactNode
cityDebouncenumberMilliseconds without typing before cities are searched. Default 250.
cityMinQuerynumberLetters needed before cities are searched when no region is chosen. Default 2.
classNamestring
defaultValuePartial<LocationValue>Initial address when uncontrolled.
disabledboolean
errorsPartial<Record<LocationField, ReactNode>>Error messages per field; a field with a message is marked invalid.
fieldsLocationField[]Which fields to show, in order. Default all four.
idstring
idPrefixstringPrefix for the field ids, so labels stay stable and two address forms on a page never clash.
labelsPartial<Record<LocationField, string>>Override field labels. The region label is replaced by the adapter's word for the country, when given.
legendReactNodeVisible group label. Without it, give the fieldset an `aria-label` if the address needs a name.
messagesPartial<LocationFieldsMessages>
onValueChange((value: LocationValue, changed: LocationField) => void)Called with the whole new value and the field that changed. Changing the country clears the rest.
requiredLocationField[]Fields that must be filled; they get `required` and the label asterisk.
valueLocationValueThe address (controlled).

Variants

PropValuesDescription
fields'('country' | 'region' | 'city' | 'postalCode')[]'Which parts to show, in order. Default all four.
allowCustomCity'true''false'Offer the typed text as a city when it is not in the list. Default true.

States

StateExposed asBehaviour
Loading–A list is loading: the combobox shows a spinner and "Loading…".
Waiting for a country–Region and city are disabled with the placeholder "Choose a country first".
Load failed–The field is replaced by a role="alert" message with a Try again button.
Invaliddata-invalid on the Field, aria-invalid="true" on the controlA field with a message in errors shows it under the control.
Disableddisabled on the fieldsetEvery part is disabled.

Interaction behaviour

  • Countries load once on mount. Choosing a country loads its regions and clears the region, city and postal code.
  • A country with no regions in the data gets an optional free-text region field.
  • Cities are searched after cityDebounce ms (default 250) once cityMinQuery letters are typed (default 2), or listed at once when a region is chosen. Superseded requests are aborted.
  • Choosing a city before a region fills in the region the city belongs to.
  • A city not in the list is offered as "Not in the list: use as typed" and stored with cityId: null.
  • Controlled with value + onValueChange, or uncontrolled with defaultValue.

Keyboard support

KeysAction
TabMoves through country, region, city and postal code in order.
ArrowDown / ArrowUpOpen and move through a list (Combobox).
EnterChoose the highlighted option.
EscapeClose the list and restore the chosen text.

Each list is a Monarch Combobox and has its full keyboard model.

Accessibility

Role
group (fieldset) of comboboxes and text inputs
Accessible name
The legend, or an aria-label on the fieldset; each part has its own visible label.
  • Each part is a Field, so labels, required state and errors are wired with htmlFor, aria-required, aria-invalid and aria-describedby.
  • Load failures are announced with role="alert" and the retry is a real button.
  • The region label follows the country, so screen reader users hear the same word sighted users see.
  • Free-text parts use autocomplete (address-level1, address-level2, postal-code).

Responsive behaviour

  • An auto-fit grid: two columns from about 30rem, one column below, down to 320px.

Theme support

  • Built from Combobox, Input, Field and Button, so it follows light, dark and more-contrast themes and the product accent.
  • The failure message uses the danger semantic tokens.

Do and don't

Do

  • Pass the AbortSignal to your requests so superseded searches stop.
  • Store the codes and verify them on the server when the form is saved.
  • Return each country’s own word for its regions from regions.

Don't

  • Do not bundle a copy of geographic lists into the app to avoid the adapter; it drifts out of date.
  • Do not require a region for countries that have none.
  • Combobox: Each list part; use it alone for a single country select.
  • Field: Label, required and error wiring for each part.
  • Input: The free-text parts.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsButton, Combobox, Field, Input

Testing coverage

  • Loads countries, then regions under the adapter’s word; choosing reports the value and the changed field.
  • Region and city wait for a country.
  • Cities are searched after the minimum letters with one debounced request, and a city fills its region.
  • A chosen region lists its cities at once.
  • A city typed freely is kept with cityId: null.
  • A country without regions gets a free-text region.
  • A failed list shows an alert and Try again reloads it.
  • Changing the country clears the other parts (controlled).
  • Required, errors, custom labels and a subset of fields; disabled; server render calls no adapter method.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/location-fields

Tests: packages/react/src/components/geo/location-fields