Okay, great! Now we know how an IME works. So what was the bug?
Notice how there was a lot of keyboard input happening for interacting with the IME — we can use the arrow keys, spacebar, enter, and more. At first, I naively believed that, since the IME is an OS program, any typing or editing would exist outside the browser, and thus the browser would be oblivious to the fact that I’m using an IME. But this isn’t the case! Each keyup/keydown in an IME is responded to both by the OS and the browser! So, when the user would hit the enter key to confirm one of their IME selections, our code would immediately process a keydown event, opening a new tab even though the user may not have been done with their search query. Not good! With the code in this state, we would be making it very cumbersome for many Square sellers to use our search box in their native language.
(Important note: This bug isn’t limited to just the enter key! If you have an input listening in on any events that coincide with how an IME is controlled, you may have a similar bug in your code.)
So how can we fix it? It took me a bit of research, but I eventually learned about two browser events that I’d never encountered before:
compositionEnd. When a user starts typing with an IME, modern browsers fire the
compositionStart event, and when the text is finally confirmed,
compositionEnd will fire (with one exception — see below). This is exactly what we need! Now we can set some state in the application about whether or not the user is currently composing some text via an IME, and if they are, we won’t use any of our own keyboard event logic. The code looks like this: