the bug, live
Your Form Submits Mid-Japanese Input
Your users press Enter to finish typing a word.
Your form thinks they pressed Send.
One if statement fixes it.
Someone sent you this link? Then a form you maintain probably fires on the Enter key that Japanese, Chinese, and Korean users press to build words — before they can finish a sentence. Five minutes here and you'll see it, understand it, and fix it.
Both panes receive the same keystrokes. The demo simulates the standard IME flow (type the reading → Space to convert → Enter to confirm). Real IMEs have more features, but the Enter step is exactly what breaks. And yes — the demo's own key handling uses the very isComposing check described below.
the scale
This isn't an edge case
Every Chinese, Japanese, and Korean sentence typed on the web goes through an IME — an input method editor that turns keystrokes into characters through a compose → convert → confirm cycle. The confirm step is the Enter key.
Rough math: internet users in China (~1.1B), Japan (~100M), and South Korea (~50M), plus Chinese, Japanese, and Korean speakers everywhere else.
On a broken form, a user trying to send 「明日の会議は10時からです」 (Tomorrow's meeting starts at 10) never gets past the first phrase. Their message leaves in shreds:
Now imagine deleting and apologizing for each of these, in every conversation, every day.
It hurts most in exactly the interfaces that bind Enter to “go”:
- Chat interfaces — messaging apps, support widgets, AI assistants. Every confirm-Enter fires a fragment. The user has to delete or explain each accidental message — assuming your app even allows that.
- AI generation tools — image, video, and code generators. Half a prompt kicks off a generation the user never wanted. They wait for a result they didn't ask for, or burn credits canceling it.
the mechanism
What the IME is doing when Enter “misfires”
Here's what typing 明日 (asu, “tomorrow”) actually looks like. Watch where Enter shows up:
The IME converts keystrokes to kana in real time. The dotted underline means: still composing, nothing final yet.
Space asks the IME for candidates. The highlight means: this is a suggestion, pick or confirm it.
Enter means “yes, this is the text I want.” The user is mid-sentence. They have not asked you to do anything yet.
key === "Enter" → submit. Message gone.Japanese is the headline example, but Chinese (Pinyin, Zhuyin) and Korean (Hangul) input run the same compose-and-confirm loop, and some European dead-key and handwriting inputs compose too. One fix covers all of them.
The bug lives in your keydown handler
For a plain <form> with no JavaScript, modern browsers mostly get this right: the confirming Enter is treated as part of the IME interaction and doesn't trigger implicit submission. (Some browsers historically got it wrong, which is how this bug became folklore among IME users.)
The problem is custom key handling. keydown fires during composition by design, so pages can react to typing. The moment your code says if (event.key === "Enter") send(), you've recreated the bug — that condition cannot tell a confirming Enter from a sending Enter. Chat boxes, Enter-to-search fields, comment forms, custom autocomplete widgets: anywhere JavaScript listens for Enter is where IME users get burned.
the fix
The fix: check isComposing
The browser already knows when an IME conversion is in progress. You just need to ask:
element.addEventListener("keydown", (event) => {
if (event.isComposing || event.keyCode === 229) {
return; // IME is composing — this Enter is not for you
}
// handle Enter for form submission here
});
event.isComposing is true whenever the user is mid-composition. The keyCode === 229 check is a fallback for Safari, which fires compositionend before keydown — so isComposing is already false when the keydown arrives. The dual check is recommended by MDN and works in all modern browsers (Chrome 56+, Firefox 31+, Safari 10.1+, Edge 79+).
Using React, Vue, or another framework?
Same check, different place to find the event object:
React
Read the flag from the native event — the synthetic event may not expose isComposing directly:
const onKeyDown = (e) => {
if (e.nativeEvent.isComposing || e.keyCode === 229) return;
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
};
Vue
v-model already waits for composition to finish before updating your data — but that does not protect your own @keydown.enter handler. Check the event yourself:
<textarea @keydown.enter="onEnter"></textarea>
onEnter(e) {
if (e.isComposing || e.keyCode === 229) return;
e.preventDefault();
this.send();
}
Or design the problem away
Some forms sidestep the whole thing:
- Submit button only — don't bind Enter to submission at all.
- Ctrl+Enter (Cmd+Enter on macOS) to send — a deliberate modifier combination never collides with IME confirmation. Enter handles line breaks and composing; the modifier sends.
beyond the browser
Not just a web bug
IME users hit the same premature “send” in desktop and mobile apps. If you build native software, the rule is identical — only the API you ask changes:
- Electron and WebView apps — many desktop apps (chat clients, editors, AI tools) are a browser engine inside. Their input handling is DOM
keydown, so theisComposingfix above applies as-is. - Truly native apps — every platform exposes “is the user composing?” under its own name. On Windows, keys the IME is consuming arrive as
VK_PROCESSKEY— value 229, the very number behind the web'skeyCode === 229fallback. On macOS, a text view has marked text while composition is active (hasMarkedTextinNSTextInputClient). Cross-platform toolkits (Qt, Flutter, and others) surface the same state through their input-method events.
Whatever the platform: ask it whether a composition is in progress before treating Enter as “send”.
the proof
Test it with a real IME — no Japanese required
Every major OS ships an IME for free, and you don't need to know a word of Japanese:
- Add a Japanese input method in your OS settings (Windows: “Microsoft IME”; macOS: “Japanese — Romaji”; Linux: ibus/fcitx with mozc).
- Switch to it in your form's text field and type
konnichiha— you'll see こんにちは composing with an underline. - Press Space (it becomes 今日は or こんにちは), then press Enter to confirm.
- If your form submitted on that Enter, you have this bug.
Live event inspector
Type below with an IME active and watch keydown and compositionstart/update/end fire — including what the fix would do with each Enter. Without an IME you'll still see keydown events; isComposing just stays false.
pass it on
Found this bug in someone else's product?
This page exists to be linked. Paste it into a bug report so the developer on the other end can see the problem, feel it in the demo, and grab the fix — no long explanation needed on your side.
Or start from this report template:
Title: Form submits while an IME is composing (Japanese/Chinese/Korean input)
Steps to reproduce:
1. Enable a Japanese IME (every OS ships one).
2. Type "konnichiha" into the affected field.
3. Press Space to convert, then Enter to confirm the conversion.
Expected: the text is confirmed; nothing is sent.
Actual: the form submits a half-finished message.
Fix (one line): ignore keydown events where
`event.isComposing || event.keyCode === 229` is true.
Demo and details: https://kai-rin.github.io/your-form-submits-mid-japanese-input/