Skip to content

Postal address

The form every Japanese business app repeats: type 123-4567, get the prefecture and city filled. The postal input wears the postal-jp mask (installMask(), auto-installed), so a guarded change trigger fires exactly once — on a complete code — and the server answers with out-of-band re-renders of the address inputs. The server owns the postal database; the client never parses addresses. Covered by the versioning policy.

Also known as: zip-code lookup, address autofill.

Try 123-4567 (single hit), 600-8216 (two candidates), or 999-0000 (no match).

Try 123-4567, 600-8216 (two candidates), or 999-0000.

<div class="hc-field">
<label class="hc-field__label" for="postal">Postal code</label>
<input class="hc-input" id="postal" name="postal" inputmode="numeric"
placeholder="123-4567" pattern="\d{3}-\d{4}"
data-hc-mask="postal-jp"
data-hx-get="/address-by-postal"
data-hx-trigger="change[target.value.length==8]"
data-hx-include="this"
data-hx-target="#postal-result">
<p class="hc-field__hint" id="postal-result" aria-live="polite"></p>
</div>
<div class="hc-field">
<label class="hc-field__label" for="pref">Prefecture</label>
<input class="hc-input" id="pref" name="pref" autocomplete="address-level1">
</div>
<!-- #city (address-level2) and #addr1 (address-line1) follow the same shape -->

The mask makes the trigger guard exact: change[target.value.length==8] can only be the complete 123-4567. Forms that prefer an explicit affordance put the same data-hx-get on a 「住所検索」 button with data-hx-include="#postal" — the responses are identical.

GET /address-by-postal?postal=123-4567:

CaseResponse (200 unless noted)
single hita status line for the hint slot + OOB outerHTML re-renders of #pref / #city / #addr1 — complete inputs, values filled, data-hx-swap-oob="outerHTML"
multiple hitscandidate <button type="button">s in the hint slot, each re-calling with &choice=<n> → single-hit shape
not founda hint line (“enter it manually”); no OOB swaps
malformed postal422 + a hint line (the standard 422 allowance swaps it)

OOB responses re-render complete inputs (class, id, name, autocomplete, value): outerHTML replaces the whole control, and the stable ids keep every <label for> association intact. Overwriting user-typed values is what autofill means.

Without JavaScript the address inputs are ordinary inputs — manual entry always works. pattern + placeholder mirror the mask so native validation stays equivalent.

  • The hint slot is aria-live="polite" — fills, candidate lists, and no-match messages are announced without stealing focus.
  • Candidate buttons are real buttons in DOM order right after the postal input.
  • autocomplete tokens stay on the inputs, so browser autofill and the lookup coexist.