Say your calculator has an amount field that turns "50M" into 50,000,000. You test it with "1.2B" typed in a mixed-unit way, and the field fills with a number whose digits have exploded. Or your chat app clears the input box the instant someone taps Send, and a user on a train whose app was killed mid-send loses a long message without a trace. Neither raises an error.
When does a field's value belong to the program?
Text a person is still typing belongs to the person — the program should transform or clear it only at the moment it is committed: when the field loses focus, when it is sent, or when the server confirms success. Touch it earlier and the person's keystrokes mix with the program's edits in one field, or text that is not yet saved anywhere disappears.
A field goes through three states:
- Typing — characters arrive one at a time; in languages that compose characters (Korean, Japanese, Chinese) the current character is not even finished
- Committed — the person left the field or tapped Send
- Safe — the server said it received it
Each thing the program does (convert, clear, release the draft) has a state it belongs to. Do it earlier and it breaks.

Why does converting on every keystroke blow up the number?
Type a mixed-unit amount one character at a time. As soon as the first unit is complete, the converter rewrites it as a full number, and the next digit you type lands after that number. You typed one unit; the field now holds a number with an extra digit glued on. Composed characters behave the same way — if the program touches a character mid-composition, the composition breaks.
- While typing, show exactly what was typed (show the converted value as a preview next to the field)
- Convert once, on blur or submit — on the web, hook the
changeevent or the submit handler, not the per-keystrokeinputevent - If you must react per keystroke, check whether composition has ended — on the web, do nothing before
compositionend - Attach a converter only to fields of that unit. Share an amount converter with a percentage or decimal field and it strips the decimal point
Why does clearing on Send lose messages?
When Send is tapped, the text is committed but not yet safe. If the network drops or the app is killed in between, the text is gone from the screen and absent from the server. If the draft is tied to the field's value, the draft is empty too.
- Clearing the visible field right away is fine (keep the snappy feel)
- But the draft must hold the sent text separately until the server confirms success
- On failure, put that text back in the field
- Anything the person types while the send is in flight is kept separately and not wiped
Keyboard hints change "typing" too
A single hint to the on-screen keyboard can block composition outright. In one mobile app, turning off suggestions on a field (Flutter enableSuggestions) made the Android keyboard treat it like a password field: Korean characters would not compose, only Latin letters and digits came through. It is easy to misdiagnose as a keyboard setting. If you only want to turn off autocorrect, use the option that does only that (autocorrect: false).
A checklist to paste in
For each input field:
[ ] Does any code change the value on every keystroke? -> move it to blur or submit
[ ] When typing composed characters (Korean, Japanese, Chinese), is the value touched mid-composition?
[ ] Is the converter shared with fields of a different unit?
[ ] Does a keyboard-hint option block composed input? (type Korean on a real device)
For each send:
[ ] Is the draft tied to the field's value? -> keep the sent text separately
[ ] Is the draft released only after server success?
[ ] On failure, does the text come back to the field?
[ ] Does text typed during the send survive?
Test order:
- Type mixed-unit values one character at a time
- Type with composed characters — on a real keyboard, not just an emulator
- Tap Send, switch to airplane mode immediately, force-quit the app and reopen it
- With a slow network, keep typing the next message while the first is sending
Three cases we ran into
- Per-keystroke conversion exploded the digits. On a calculator site, the amount field converted the first part of a mixed-unit value while it was still being typed, and the next characters were appended. We caught it in a full desktop test by typing unit combinations one character at a time, and moved conversion to blur.
- Clearing on Send emptied the draft. In a chat app, after switching to clear-on-send, a review found the draft was tied to the field value, so killing the app mid-send lost the text. The draft now holds the sent text until the server confirms.
- Turning off suggestions blocked Korean. In the same app, a name field would not accept Korean, and we suspected the keyboard settings. The cause was the suggestions-off option on that field.
In all three, the program did exactly what it was told. It just acted before the person was done.
PreviousA cache only knows what is in its keys and tags — list what the result really depends on, then match keys and invalidation to it