@ph-dev-utils/address-react
v0.3.0
Published
React cascading Philippine address picker (region → province → city → ZIP). <PhAddressPicker> + usePhAddress(), built on @ph-dev-utils/address-core.
Downloads
412
Maintainers
Readme
@ph-dev-utils/address-react
React cascading Philippine address picker — region → province → city/municipality → ZIP, with ZIP autofill. Handles NCR (no provinces), independent cities, and multi-ZIP cities correctly.
npm install @ph-dev-utils/address-reactComponent
import { PhAddressPicker, type AddressValue } from '@ph-dev-utils/address-react';
import '@ph-dev-utils/address-react/theme.css'; // optional styled preset
<PhAddressPicker
onChange={(v: AddressValue) => console.log(v)}
defaultValue={{ cityCode: '072217' }} // optional: seed an edit form (region/province/zip auto-derived)
/>Props
| Prop | Type | Default | Notes |
|------|------|---------|-------|
| onChange | (v: AddressValue) => void | — | Fires on every change (not on mount) |
| defaultValue | { regionCode?, provinceCode?, cityCode?, zip? } | — | Uncontrolled seed; cityCode alone hydrates the whole cascade |
| zipPolicy | 'first' \| 'none' | 'first' | Autofill first candidate ZIP, or leave blank |
| showZip | boolean | true | Render the ZIP field |
| showBarangay | boolean | false | Render the barangay field (lazy-loads per city from jsDelivr) |
| searchable | boolean | false | Type-to-filter combobox for the long lists (city/municipality + barangay) instead of a native <select> — a province can hold 50+ municipalities |
| fetchBarangays | (cityMunCode) => Promise<{code,name}[]> | jsDelivr | Override the barangay source (self-host / mirror) |
| labels / placeholders | { region?, province?, city?, barangay?, zip? } | English | For i18n / Tagalog |
| disabled required id className | — | — | Standard form props |
AddressValue
interface AddressValue {
region: { code; name } | null;
province: { code; name } | null; // null is valid (NCR / independent cities)
city: { code; name; isCity } | null;
barangay: { code; name } | null; // v0.2
zip: string | null; // autofilled, user-overridable
zipOptions: string[]; // all candidate ZIPs for the city
}Hook
For custom UI, use the headless hook (same logic, your markup):
import { usePhAddress } from '@ph-dev-utils/address-react';
const { value, options, zipAmbiguous, selectRegion, selectProvince, selectCity, setZip, reset }
= usePhAddress({ onChange, defaultValue });Searchable (typeahead) fields
<PhAddressPicker searchable />searchable swaps the city/municipality and barangay fields for an accessible type-to-filter combobox (WAI-ARIA combobox + listbox: arrow keys, Enter to select, Esc to revert, selection always resolved by PSGC code). Region and province stay native <select> since they are always short. The standalone Combobox is also exported if you want it elsewhere. Note: a combobox trades the native mobile picker wheel for searchability — leave it off (the default) if your audience is mostly mobile and your lists are short.
Styling
Ships unstyled with .ph-ap* class names. Import @ph-dev-utils/address-react/theme.css for a default PH-themed look, or target the classes yourself. The theme is recolorable via --ph-ap-* CSS custom properties. SSR-safe (useSyncExternalStore, no window/fetch at import). The theme covers the searchable combobox (.ph-ap__combobox, .ph-ap__listbox, .ph-ap__option).
Notes
- NCR hides the province step (
province: nullis valid). Independent cities (Isabela, Cotabato) are reachable in their region. - Multi-ZIP cities (Manila ~200, Davao 12): the ZIP is autofilled but editable, with a candidate dropdown when
zipAmbiguous. ZIP data is community-sourced (GeoNames), not an official PHLPost feed. - Barangay (opt-in via
showBarangay) lazy-loads a city's barangays from the jsDelivr CDN (@ph-dev-utils/address-data) — zero network unless enabled; optional, with a loading/error hint.
License
MIT (code). Bundled ZIP data © GeoNames, CC BY 4.0.
