Address autocomplete widget
One script tag wires Canadian address search into an existing form. It finds the
address field, fills the address on selection, and emits the riding. The widget calls
/api/search, which must be enabled on this deployment.
Quick start
<script src="https://cancoder.chesterhillsolutions.ca/embed.js" data-province="ON" defer></script>
That is the whole integration. On load the widget finds the address field in each
<form>, attaches, and handles the rest.
Script tag attributes
| Attribute | Effect |
|---|---|
data-auto | Set to false to disable auto-attach and wire forms yourself with the JavaScript API. |
data-key | Public browser key (pk_…). Required when browser keys are enabled; pairs with an origin allowlist and a daily cap. |
data-province | Restrict suggestions to a province/territory code (for example ON). |
data-limit | Maximum suggestions to request per keystroke. Defaults to the API default. |
data-include-province | Set to true to resolve the riding as well as the address (uses /api/combined). |
data-demo | Set to true to resolve via the keyless /api/demo/* tier — intended for marketing try-its, not production. |
data-endpoint | Override the API origin the widget calls. Defaults to the script’s own origin. |
data-theme | Force light or dark. Omit to follow the operating-system preference. |
Field detection
The standard autocomplete attribute wins, since it is an explicit statement of
intent; otherwise name/id/placeholder/aria-label/<label>
are matched against per-field patterns. Detection is deliberately conservative: it skips
address-line2, unit/apt, country, and email fields, and matches on word boundaries
so prov matches but improve does not.
Filling works on React/Vue controlled inputs: values are written through the prototype setter
and followed by real input/change events, so framework state actually
updates instead of silently reverting. A province <select> is matched on
either the code (ON) or the full name (Ontario).
JavaScript API
For forms detection cannot read, attach explicitly:
const widget = RidingLookup.attach({
form: '#checkout',
input: '#addr1', // optional; auto-detected within `form`
fields: { // any of these override detection
city: '#city', province: '#prov', postal: '#pc',
riding: '#riding_hidden' // not auto-detected: bind it to have the riding written in
},
province: 'ON',
includeProvince: false, // true -> resolve via /api/combined
demo: false, // true -> resolve via /api/demo/* (keyless; marketing)
fill: true, // false -> emit events only, touch nothing
locationBias: { lat: 43.65, lon: -79.38 },
onSelect(s) {}, onRiding(r) {}, onError(e) {}
});
widget.destroy(); // restores the field exactly as found
Events
Events bubble from the input, so one delegated listener covers every form on the page.
| Event | detail |
|---|---|
ridinglookup:select | The chosen suggestion, fired for containers and addresses alike. |
ridinglookup:riding | { riding, properties, provinceData, point, suggestion } |
ridinglookup:error | { error } |
document.addEventListener('ridinglookup:riding', (e) => {
console.log(e.detail.riding); // "Toronto Centre"
});
Behaviour worth knowing
- Selecting a street container does not close the dropdown — it drills into that street and keeps searching within it.
- Requests are debounced (150 ms) and superseded ones are aborted, so a slow early keystroke can never overwrite a later result.
- The dropdown renders in a shadow root, so host-page CSS cannot break it.
Authentication
The widget runs in a browser, so it cannot hold a secret. Use a public browser
key (pk_…), which pairs with a server-enforced origin allowlist and a
daily cap:
<script src="https://cancoder.chesterhillsolutions.ca/embed.js" data-key="pk_live_…" defer></script>
Your backend should keep calling the API with BASIC_AUTH (or a server key):
that credential is not origin-restricted and not daily-capped, and never belongs in a
browser.
See also
- API reference — every endpoint, parameter, and error code.
- OpenAPI document — machine-readable spec.