Phone numbers the way Japan writes them
A Japanese phone number starts with 0 and has 10 digits, or 11 for a mobile phone, and where the hyphens go depends on the area code. Forms built elsewhere get three things wrong: a check that expects one hyphen pattern, a +81 number that keeps the 0, and a mobile check that knows only 070, 080 and 090. Check the length, not the hyphens, and convert the number once:
// 11 digits after 0A0 (mobile, 050)
// and 0800; 10 for everything else
const LONG = /^0(?:[1-9]0|800)/;
function toE164(value) {
const n = toAsciiNumber(value)
.replace(/[-()]/g, "")
.replace(/^\+810?/, "0");
const digits = LONG.test(n) ? 11 : 10;
if (!/^0(?!10)[1-9]\d+$/.test(n) ||
n.length !== digits) {
return null;
}
return "+81" + n.slice(1);
}
toE164("090-1234-5678") returns "+819012345678". It uses toAsciiNumber from the full-width digits page, so it also takes the full-width digits and dashes a Japanese input method types.
10 digits, or 11
From the ministry in charge of phone numbers, the Ministry of Internal Affairs and Communications: a landline number is 0, the area code, the local exchange code and a four-digit subscriber number, and the area code and the local exchange code have five digits between them. That makes 10. Numbers that start with 0, a digit other than 0, then 0 (070, 080, 090, and others) are for mobile phones, IP phones and the like; mobile numbers have 11 digits. Free-call numbers starting with 0120 have 10 digits, and those starting with 0800 have 11. Numbers starting with 00 select a carrier, and 010 starts an international call; neither is a phone number. LONG encodes this, and libphonenumber, Google's phone number library, agrees that 050 numbers have 11.
We ran toE164 on a number for each of the 387 area codes in the ministry's list of area codes (March 1, 2026): each came out with 10 digits, and with one digit more each was rejected. The check is on the length only. It catches a digit left out or typed twice; for a check against the numbers in use, use libphonenumber.
The hyphens move with the area code
| Where | Written |
|---|---|
| Tokyo | 03-XXXX-XXXX |
| Yokohama | 045-XXX-XXXX |
| Asahikawa | 0166-XX-XXXX |
| Izu Ōshima | 04992-X-XXXX |
| Mobile | 090-XXXX-XXXX |
| Free call | 0120-XXX-XXX |
Area codes have one to four digits after the 0. The ministry's list has 3 of one digit (03, 04 and 06), 48 of two, 296 of three and 40 of four, and the local exchange code is as much shorter as the area code is longer. A mask of 3, 4 and 4 digits fits mobile numbers and rejects every landline, which has 10.
Don't put the hyphens in yourself. Accept the number with or without hyphens, spaces or brackets, store the digits or the +81 form, and show the number as the person typed it. libphonenumber's data for Japan has 16 formats and picks one by the leading digits, from lists of area codes; its formatter does this if you need it.
+81 and the 0
The ministry's Q&A: from abroad, you dial the country code 81 and leave out the 0 in front of the area code, so a Tokyo number is dialed from the US as 011-81-3-3504-XXXX, and a mobile number as 011-81-90-XXXX-XXXX. In the international E.164 format (Twilio's explanation), that is a +, the country code and the number, at most 15 digits: 090-1234-5678 is +819012345678. Putting +81 in front of the number as typed gives +8109012345678, which is not the person's number.
A form with a country picker set to +81 still gets the number with its 0, because that is how people in Japan know it. toE164 drops it, and also reads numbers already written with +81, with or without (0). In Node.js 24 and in Chromium 152:
| Typed | toE164 |
|---|---|
090-1234-5678 | +819012345678 |
090ー1234ー5678 | +819012345678 |
03(1234)5678 | +81312345678 |
+81 (0)3-1234-5678 | +81312345678 |
090-1234-567 | null |
1234-5678 | null |
The last one has no area code. People calling within their own area dial the number without it (the same Q&A), so it may be how someone knows their own landline number. Ask for the area code rather than guess it.
The field
<input type="tel" autocomplete="tel-national">
MDN's page on type="tel": the browser does not check its value against a format, "because formats for telephone numbers vary so much around the world", and phones may show a keypad for phone numbers. In Chromium 152, full-width digits inserted into it stayed full-width and the field was still valid, so normalize before you check.
In the HTML standard, tel is the full number with the country code, and tel-national is the number without it, "with a country-internal prefix applied if applicable": for Japan, with the 0. A field for the number as people in Japan write it, alone or after a country picker, is tel-national; a field that takes +81 is tel.
060 mobile numbers are coming
Japan is running out of 070, 080 and 090 numbers. On December 20, 2024, the ministry changed the numbering plan so that carriers can be given 11-digit mobile numbers starting with 060-1 to 060-9 (its page on 060). The carriers announced on July 8, 2026 that the start is postponed, and the ministry is urging them to be ready by the end of the 2026 fiscal year, in March 2027. A check such as /^0[789]0/ will reject these numbers.
libphonenumber's pattern for Japanese mobile numbers covers all of 060-1 to 060-9 from release 9.0.32 (June 3, 2026); earlier releases matched only a few 060 numbers, or none. If you use it, or a library built on its data, check that your copy is 9.0.32 or later. When you need a mobile number, for SMS, check the converted number with the same pattern:
// Mobile numbers, as libphonenumber
// 9.0.32 and later match them
const MOBILE = /^\+81[6-9]0[1-9]\d{7}$/;
MOBILE.test(toE164("060-1234-5678")) is true, and so is 090; 050 and landlines are false.
The rest of a Japanese check
A phone number that is rejected, or turned into a number that SMS can't reach, stops people at sign-up. The same pass catches Enter while typing Japanese (the fix), yen charged 100 times over (the fix), kanji drawn in their Chinese shapes (the fix), headings that break in the middle of a word (the fix), postal codes rejected when typed in Japanese (the fix), dates saved one day early in Japan (the fix), address forms in the American order (the fix), PDFs with the Japanese missing (the fix), search that finds nothing in Japanese (the fix), previews cut down to “...” in Japanese (the fix), lists sorted in the wrong order (the fix), email subjects that arrive garbled (the fix), CSV files that open garbled in Excel (the fix), Japanese titles that give an empty URL slug (the fix), file names garbled on upload and download (the fix), dates in the Japanese era that come out wrong (the fix), full-width spaces that get past your checks (the fix), public holidays your app gets wrong (the fix), and vertical text that comes out sideways or upside down (the fix).
Lesstep translates web apps into Japanese and delivers them as one pull request. In Complete (US$249), we make your phone fields take numbers as people in Japan write them, convert them to +81 without the 0 where you send SMS, and accept 060 numbers, in the same pull request. The first step is a free sample.
Google is a trademark of Google LLC; Twilio is a trademark of Twilio Inc.; Node.js is a trademark of the OpenJS Foundation. This page is not affiliated with or endorsed by any of them.
More: Enter sends the message while typing Japanese · Stripe charges 100 times too much in yen · Kanji in their Chinese shapes · Japanese headings that break in the middle of a word · Forms that reject numbers typed in Japanese · Dates that come out wrong for Japanese users · Address forms in the Japanese order · Japanese text missing from your PDFs · Search that finds nothing in Japanese · Length limits that break in Japanese · Japanese lists sorted in the wrong order · Japanese email subjects that arrive garbled · Japanese CSV files that open garbled in Excel · Japanese titles that give an empty URL slug · Japanese file names garbled on upload and download · Japanese era dates that come out wrong · Full-width spaces that get past your checks · Japanese public holidays your app gets wrong · Japanese vertical text that comes out sideways or upside down · Japanese localization checklist · Japanese localization for your web app