Thiya11/nihonpost: TypeScript-first Japanese postal code (郵便番号) lookup with address autofill and a Vue 3 composable. Ze

github.com · 2026-07-13 · by Long Nguyen ·github
TypeScript-first Japanese postal code (郵便番号) lookup with address autofill and a Vue 3 composable. Zero dependencies, fully typed. - Thiya11/nihonpost

Thiya11/nihonpost

TypeScript-first Japanese postal code (郵便番号) lookup with address autofill and a Vue 3 composable. Zero dependencies, fully typed. - Thiya11/nihonpost

1 stars · 0 forks · TypeScript Topics: japanese, postcode, zipcode, postalcode, yubinbango, yubin, jposta

README

🗾 nihonpost Japanese postal code → address lookup for Vue 3. TypeScript-first · works out of the box · fully self-hostable (offline, zero third-party calls) · self-updating data · handles 〒 and full-width input 〒150-0002 → { prefecture: "東京都", city: "渋谷区", town: "渋谷" }

Why nihonpost? Every Japanese web form needs 郵便番号 → 住所 autofill. Your options today:

API-based (zipcloud etc.) yubinbango-core2 nihonpost

Works offline / no third-party dependency ❌ ✅ ✅ when self-hosted

Zero-config first run (CDN fallback) — ❌ ✅

TypeScript types ❌ ❌ ✅

Vue 3 composable ❌ ❌ ✅

Promise-based ❌ ❌ (callbacks) ✅

Full-width & 〒 input normalization ❌ partial ✅

Full-width kana output (シブヤ not シブヤ) ❌ ❌ ✅

Data auto-updated monthly via CI — ❌ ✅

Install npm i nihonpost Quick start (Vue 3) <script setup lang="ts"> import { usePostalCode } from 'nihonpost/vue'

const { code, address, loading, notFound } = usePostalCode() </script>

<template> <label>郵便番号</label> <input v-model="code" placeholder="150-0002" />

<span v-if="loading">検索中…</span> <span v-if="notFound">該当する住所が見つかりません</span>

<template v-if="address"> <input :value="address.prefecture" readonly /> <input :value="address.city" readonly /> <input :value="address.town" readonly /> </template> </template> That's it. The composable watches code, normalizes whatever the user types (〒150ー0002 works), and fills address the moment 7 digits exist. Composable API const { code, // Ref<string> — bind to your input normalized, // ComputedRef<string|null> — "1500002" when valid address, // ComputedRef<JpAddress|null> — first match addresses, // ShallowRef<JpAddress[]> — all matches (some codes span 2 cities!) loading, // Ref<boolean> notFound, // Ref<boolean> — valid code, no match error, // Ref<Error|null> search, // (value?) => Promise<JpAddress|null> — manual trigger reset, // () => void } = usePostalCode({ auto: true, // lookup automatically at 7 digits (default) debounce: 0, // ms; rarely needed since length is fixed }) Framework-agnostic core No Vue? Use the core directly: import { lookup, lookupAll, formatPostalCode } from 'nihonpost'

const addr = await lookup('150-0002') // { prefecture: '東京都', city: '渋谷区', town: '渋谷', // prefectureKana: 'トウキョウト', cityKana: 'シブヤク', townKana: 'シブヤ', // prefectureCode: 13 }

await lookupAll('4980000') // → 2 results: 愛知県弥富市 AND 三重県桑名郡木曽岬町 (shared codes are real!)

formatPostalCode('1500002') // "150-0002" Data loading The dataset (~124k codes) is chunked by the first 3 digits into ~900 small JSON files — your app loads only the chunks it touches, a few KB each. Zero config: it works out of the box. With no setup, lookups fetch chunks from the jsDelivr CDN, pinned to your installed nihonpost version (a one-time console.info reminds you this is happening). Upgrading the package automatically moves the pin — nothing goes stale. // Equivalent explicit form, if you prefer no console notice: import { configureLoader, cdnLoader } from 'nihonpost' configureLoader(cdnLoader()) Self-hosting (offline, intranet, CSP, privacy policies): copy node_modules/nihonpost/data into your static assets and point the loader at it once, at app startup: import { configureLoader, fetchLoader } from 'nihonpost'

configureLoader(fetchLoader('/nihonpost-data')) // lookups now GET /nihonpost-data/150.json etc., cached after first hit Vite example — add to vite.config.ts: import { viteStaticCopy } from 'vite-plugin-static-copy'

plugins: [ viteStaticCopy({ targets: [{ src: 'node_modules/nihonpost/data/*', dest: 'nihonpost-data' }], }), ] Any static host works too (GitHub Pages, Cloudflare Pages, S3). It's static files — there is no API server anywhere.

Bundle size note: none of this data ever enters your JS bundle. The browser fetches only the chunks a lookup touches — a few KB each, cached after the first hit. The full ~11 MB exists only in node_modules (and travels as a 1.9 MB tarball).

Custom sources implement one function: configureLoader(async (prefix) => { const res = await fetch(`https://cdn.example.com/jp-postal/${prefix}.json`) return res.ok ? res.json() : null }) Rebuilding the data yourself npm run build:data # downloads latest utf_ken_all from Japan Post npm run build:data -- ./my.csv # or use a local copy The pipeline handles KEN_ALL's sharp edges: multi-row 町域 continuation merging, parenthetical annotation stripping, 「以下に掲載がない場合」 placeholders, half-width → full-width kana, and deduplication. A GitHub Action rebuilds the data on the 1st of every month and publishes a patch release automatically — installs stay current without a server. Notes & limits

Postal codes resolve to town (町域) level — that's how Japan's postal system works. Users still type the block/building portion themselves. Some codes map to multiple municipalities; address gives the first, addresses gives all. Offer a picker if you need precision. Data source: Japan Post 郵便番号データ (public data).

License MIT © Thiyagu Arunachalam

source

github.com · 1 images · 111 links

Comments (0)

No comments yet