Search topics
Form fields that reject full-width digits without saying why
A checkout's phone field takes only the digits 0 to 9, so the same number typed with a Japanese input method on, in full-width digits, is called invalid or deleted as it is typed.
/^[0-9]{10,11}$/.test(tel.value) The problem
People typing with a Japanese input method on have a correct phone number refused, or deleted as they type it, with nothing to say why.
A shop's checkout asks for a phone number, so the courier can call. A customer types it with Japanese input on, as they were typing their address a moment before. In hiragana mode, a Japanese input method can type digits at full width, depending on its settings: 0123456789 rather than 0123456789. They are the same digits to anyone reading them, drawn a little wider, each one the width of a kana. A number copied from a document written in Japanese can be full-width too.
The field's script knows only the half-width digits 0 to 9, and sites write it in one of two common ways:
- It checks the number when the form is sent, and refuses it with "Enter a valid phone number." The customer reads the number back, finds the right digits, sends it again, and gets the same message. Nothing says that the number is right and only its width is wrong.
- It keeps the field to digits with an
inputhandler that deletes everything else. Full-width digits are not 0 to 9 to that handler, so they vanish from the field as they are typed, with no message. A hyphen typed in hiragana mode comes out as ー, the long vowel mark, and goes the same way.
The digits are not the error: the field refuses a value in a form it hasn't asked for, so the failure is in what the page says about it.
Success Criterion 3.3.3 Error Suggestion asks that when an input error is detected and a way to correct it is known, the correction is suggested. The page knows exactly what it wants, half-width digits, since that is the only thing its check tests for, and "Enter a valid phone number" doesn't say it. Its Understanding document names the people this is for: people with cognitive disabilities, who may find it hard to understand how to correct an error, and people with visual disabilities, who may not be able to work out exactly how. A width they can barely see is a correction neither group can guess.
Success Criterion 3.3.1 Error Identification asks that an input error the page detects is identified, and described to the person in text. The first Before meets it: the message names the field and says it is not valid, which the Understanding document accepts ("Email is not valid" passes 3.3.1). The second doesn't. Its handler detects the characters it won't accept and deletes them, and no text says so anywhere. The Understanding document covers a page that changes a value by itself: the error still has to be described to the person.
Everyone who types Japanese can meet this, whatever their abilities: an input method that types full-width digits is a setting, not a mistake. Those listed below are the people for whom it costs the most.
4 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (affected)
- Reach, strength (not affected)
- Cognitive (affected)
- Seizures (not affected)
- Limited language, cognitive and learning abilities The message says the number is wrong, and it is the right number. Nothing points at the width, so people type the same digits again, meet the same message, and may give up on the form.
- Limited vision Full-width digits differ from half-width ones mainly in the space each one takes. Under magnification, with only part of the field in view, that difference is easy to miss, and so are digits that vanish from the field as they are typed.
- Without vision Nothing in the message tells a screen reader user to check the width of the digits, and where a handler deletes them as they are typed, nothing says so: the field is empty when they send the form, and the message only calls the number invalid.
- Limited manipulation People who type slowly, with one hand or with a switch, spend many presses on a phone number. A refusal costs them the whole number again, and switching the input method off is another step.
The field has a label, the message is tied to it, and the page passes a scan: nothing in the markup is wrong. A scan never types, and someone testing without a Japanese input method only ever types half-width digits, so the check always passes. AI assistants asked for "a phone field that only accepts numbers" can write one of the two Befores below. EaseWeb's audit sets the full-width number into each field that asks for digits and sends an input event, then reports a field whose handler deletes it with no words about width (3.3.1), and a field whose pattern refuses it while the browser checks the form and nothing near the field names the width (3.3.3). The audit never sends a form, so on the parts of a page written in Japanese, other phone, postcode and kana fields are listed for a person to try.
Try it
Type the phone number with the Japanese input above the form, then press Continue.
Broken 1: does the page take the number, and if not, does it say why? The input method types it in full-width digits, the same number to anyone reading it. Then type 0123456789 yourself and compare.
Broken 2: type with the input method again and watch the field as the digits go in. Does the page say what happened?
Apply a fix. Type with the input method and press Continue: does the page take the number, or say which digits to use?
Broken Can you fix this?
The fix
Convert full-width digits before checking the number, or say to use half-width ones.
- 1Convert full-width digits and hyphens before checking, or name the width in the message.
- 2Never delete characters from a field as they are typed.
- 3Check again on the server, with the same conversion and the same words.
A check that says only that the number is invalid
<form> <label for="tel">Phone number</label> <input id="tel" name="tel" type="tel" autocomplete="tel" aria-describedby="tel-error"> <p id="tel-error"></p> <button type="submit">Continue</button></form>Convert the digits, then check them
<form> <label for="tel">Phone number</label> <input id="tel" name="tel" type="tel" autocomplete="tel" aria-describedby="tel-error"> <p id="tel-error"></p> <button type="submit">Continue</button></form>Why this fix: Convert what people type instead of rejecting it
The check accepts only the half-width digits 0 to 9, so 0123456789 fails it, and the message says the number is invalid without saying that half-width digits would pass.
normalize('NFKC') is Unicode's compatibility normalization, and among other things it turns full-width digits, the full-width hyphen and the full-width space into their half-width forms, so 0123456789 becomes 0123456789. The replace then takes out spaces and the dashes people type between groups, ー among them, which normalization leaves as it is. The number is checked after that, so the same number passes in either width, and the field is given the converted digits, which the form sends. A number that is still wrong, such as one with nine digits, gets a message that says what to enter. There is no input handler, so nothing is deleted as people type. Convert the number the same way on the server, since a request can reach it without this script.
Both pass 3.3.1 and 3.3.3. Converting the number is the one to use: the number was right, and converting it takes one line of code, no more than the second fix needs to notice the full-width digits, and the second fix spends its line on a message instead of on the number. Saying which digits to use is for a field whose rules you can't change, such as a form that posts to a system that refuses anything else; it leaves everyone who types in Japanese to type the number twice.
Convert when the form is sent, or when the field loses focus, not in an input handler. While a conversion is in progress the text belongs to the input method, and a handler that rewrites the value then interferes with what the person is typing. If you do convert as people type, skip the events where event.isComposing is true, as the guide on Enter during IME conversion does for its key handler.
The first fix gives the field back the converted digits, so the form sends the number in the form you store. Where you show it back to the person, such as on a confirmation page, keep it recognisable: GOV.UK's telephone number pattern reports people confused when shown a reformatted version of the number they gave.
If the field has a pattern for the browser's own check, the browser tests the value as typed, before any script converts it. Either let the pattern take both widths ([0-90-9]{10,11}) and convert on the server, or leave pattern off and check in the submit handler after converting. A pattern that takes only 0 to 9 brings back the first Before, with the browser's generic "match the requested format" message in place of yours.
Apply NFKC only to fields whose form you decide, such as phone numbers, postcodes and card numbers. It changes more than width: ① becomes 1 and ㈱ becomes (株), which is not what someone meant in a name or an address. Python's unicodedata.normalize, Java's Normalizer and PHP's Normalizer (in the intl extension) all offer the same NFKC form for the server.
type="tel" and inputmode="numeric" bring up a keypad on phones, which types half-width digits, but a number that is pasted, or typed on a computer with a Japanese input method on, can still be full-width, so the field still converts it.
Verify the fix
6 checks, no mouse.
Test with: Input method (IME), Keyboard, Screen reader
Record the OS, browser, input method and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared form field or its validation changes.
Limits
This is a starting pattern, not a guarantee for every application. The example is one phone field with a fixed number of digits; postcodes, card numbers and amounts need their own rules after the conversion, and a number with a country code needs a + kept. The replace takes out spaces and dashes, not brackets, so a number written as 03(1234)5678 gets the message; add brackets to it if your customers write them. A kana field that refuses hiragana or half-width katakana is the same failure: NFKC turns half-width katakana into full-width, and each hiragana letter becomes its katakana by a fixed step in Unicode, but that field has no guide of its own yet. How a message reaches people after a failed submission, by focus or by an error summary, is covered in form errors that don't say how to fix them.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
References
- WCAG Understanding: error-identification (opens in a new tab)
- WCAG Understanding: error-suggestion (opens in a new tab)
- WCAG Technique G85 (opens in a new tab)
- WCAG Technique G177 (opens in a new tab)
- developer.mozilla.org: normalize (opens in a new tab)
- unicode.org: tr15 (opens in a new tab)
- design-system.service.gov.uk: telephone-numbers (opens in a new tab)
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.