Enter sends the message while someone is typing Japanese
Japanese is typed through an input method (IME). You type nihon, it shows 日本 underlined, and you press Enter to confirm it. A chat box or form that sends on Enter without checking for this sends the half-typed text, or sends after every word. The fix is one check at the top of your keydown handler, from MDN's keydown event:
if (event.isComposing ||
event.keyCode === 229) return;
Why both checks
isComposing is true for a key pressed while the IME is still composing, after compositionstart and before compositionend. On its own it is not enough. From the same MDN page: compositionend may fire before the keydown of the key that closes the IME, and then isComposing is false even though the key was part of composition. keyCode is still 229 in that case, so check it as well, although it is deprecated.
That is what Safari on macOS does with the Enter that confirms a word. WebKit's bug 165004 (2016) reports the composition events arriving before keydown on macOS. WebKit turned on the standard order in April 2026 (bug 311717) and turned it off again everywhere in June after "too many regression reports" (bug 317127). Keep the keyCode check.
Send on keydown, never on keyup
From MDN's keyup event: keyup events do not have special keyCode values for IME events, and compositionend may fire before keyup too. A keyup handler cannot tell the Enter that confirms a word from the Enter that sends. Move it to keydown. In Vue, @keyup.enter="send" is the common way to get this bug.
React
React's keyboard event has keyCode but no isComposing; read that from nativeEvent.
function onKeyDown(e) {
if (e.key !== "Enter" || e.shiftKey)
return;
if (e.nativeEvent.isComposing ||
e.keyCode === 229) return;
e.preventDefault();
send();
}
<textarea
value={text}
onChange={(e) =>
setText(e.target.value)}
onKeyDown={onKeyDown}
/>
Vue
<textarea v-model="text"
@keydown.enter.exact="onEnter" />
function onEnter(e) {
if (e.isComposing ||
e.keyCode === 229) return;
e.preventDefault();
send();
}
.exact leaves Shift+Enter alone, so it still makes a new line.
Plain JavaScript
input.addEventListener("keydown",
(event) => {
if (event.key !== "Enter" ||
event.shiftKey) return;
if (event.isComposing ||
event.keyCode === 229) return;
event.preventDefault();
send();
});
In a unit test, new KeyboardEvent("keydown", { key: "Enter", isComposing: true }) covers the first check. The Safari case, where isComposing is false and only keyCode is 229, needs a real browser.
See the bug yourself, without knowing Japanese
Every Mac and Windows PC comes with a Japanese input method. You only need to turn it on.
- Mac: Apple menu, System Settings, Keyboard, then under Text Input click Edit. Click the add button, select Japanese, then Japanese – Romaji, and click Add (Apple's Set up a Japanese input source). Switch to it from the Input menu in the menu bar.
- Windows 11: Settings, Time & language, Language & region, Add a language, Japanese. Switch to it with Windows key + Space. If the taskbar shows A, press Alt + ` (the key left of 1) to turn Japanese input on; it then shows あ (Microsoft's Microsoft Japanese IME).
Then, in your chat box or form, type nihon. It appears underlined, as にほん or already as 日本. Press Enter once: it should only lose the underline. Press Enter again: now it may send. Try it in Safari as well as Chrome, because the two send that first Enter differently.
The rest of a Japanese check
The Enter key is usually the first thing Japanese users report, not the only one. Without lang="ja", browsers can draw some kanji in their Chinese shapes (the fix); Japanese headings break in the middle of a word (the fix); phone numbers come in with full-width digits (the fix); dates are saved one day early in Japan (the fix); address forms ask for the street before the postal code (the fix); a +81 phone number keeps its 0 (the fix); generated PDFs lose their Japanese (the fix); search 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); vertical text that comes out sideways or upside down (the fix); and Stripe counts yen in whole yen, not cents (the fix).
Lesstep translates web apps into Japanese and delivers them as one pull request. In Complete (US$249), we type Japanese into every input in Chrome and in WebKit, and fix this and the rest in the same pull request. The first step is a free sample.
Mac, macOS and Safari are trademarks of Apple Inc.; Windows is a trademark of Microsoft Corporation. This page is not affiliated with or endorsed by Apple Inc. or Microsoft Corporation.
More: 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 phone numbers in forms · 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