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.

live demo — no Japanese keyboard required goal: send 「明日の会議は10時からです」 (“Tomorrow's meeting starts at 10”)
Press ▶ Watch it happen below — or just start typing any letters; the simulated IME turns them into Japanese.
✗ Broken formsends on every Enter0 fragments
Send
✓ Fixed formchecks isComposing0 messages
Send

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.

1.5B+
people are online in a language that requires an IME
≈ 1 in 5
of all internet users worldwide type through a composition step
0
user-side workarounds — the IME needs Enter; only your code can tell “confirm” from “send”

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”:

the mechanism

What the IME is doing when Enter “misfires”

Here's what typing 明日 (asu, “tomorrow”) actually looks like. Watch where Enter shows up:

1 · compose
asu
あす

The IME converts keystrokes to kana in real time. The dotted underline means: still composing, nothing final yet.

2 · convert
Space
明日

Space asks the IME for candidates. The highlight means: this is a suggestion, pick or confirm it.

3 · confirm
Enter ⏎
明日

Enter means “yes, this is the text I want.” The user is mid-sentence. They have not asked you to do anything yet.

✓ what the user meantConfirm this word, then keep typing.
✗ what the broken form heardkey === "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:

The rule: never let a bare Enter keypress trigger submission without checking whether the user is composing text.

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:

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:

  1. Add a Japanese input method in your OS settings (Windows: “Microsoft IME”; macOS: “Japanese — Romaji”; Linux: ibus/fcitx with mozc).
  2. Switch to it in your form's text field and type konnichiha — you'll see こんにちは composing with an underline.
  3. Press Space (it becomes 今日は or こんにちは), then press Enter to confirm.
  4. 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/