downshift-js / downshift-js/downshift

Japanese IME not working when controlling `inputValue` in `useCombobox`

Open
#1,452 5 comments 4 reactions 0 assignees View on GitHub
bug
Dominant language
JavaScript
Stars
12.3k
Forks
936
PR merge metrics
No merged PRs in 30d

Description

- `downshift` version: 6.1.12
- `node` version: 14.19.0
- `yarn` version: 1.22.17

**Relevant code or config**

```tsx
type Book = { author: string; title: string };

const books: Book[] = [
{ author: 'Harper Lee', title: 'To Kill a Mockingbird' },
{ author: 'Lev Tolstoy', title: 'War and Peace' },
{ author: 'Fyodor Dostoyevsy', title: 'The Idiot' },
{ author: 'Oscar Wilde', title: 'A Picture of Dorian Gray' },
{ author: 'George Orwell', title: '1984' },
{ author: 'Jane Austen', title: 'Pride and Prejudice' },
{ author: 'Marcus Aurelius', title: 'Meditations' },
{ author: 'Fyodor Dostoevsky', title: 'The Brothers Karamazov' },
{ author: 'Lev Tolstoy', title: 'Anna Karenina' },
{ author: 'Fyodor Dostoevsky', title: 'Crime and Punishment' },
];

function getBooksFilter(inputValue: string | undefined) {
return function booksFilter(book: Book) {
return (
!inputValue ||
book.title.toLowerCase().includes(inputValue) ||
book.author.toLowerCase().includes(inputValue)
);
};
}
export const Example = () => {
const [items, setItems] = React.useState(books);
const [inputValue, setInputValue] = React.useState('');
const {
isOpen,
getToggleButtonProps,
getLabelProps,
getMenuProps,
getInputProps,
getItemProps,
getComboboxProps,
} = useCombobox({
onInputValueChange(chg) {
setInputValue(chg.inputValue || '');
setItems(books.filter(getBooksFilter(chg.inputValue)));
},
inputValue, // Controlling inputValue here introduces IME composition issue
items,
itemToString(item) {
return item ? item.title : '';
},
});

return (



Choose your favorite book:



{isOpen ? <>↑ : <>↓}




    {isOpen &&
    items.map((item, index) => (

  • {item.title}
    {item.author}

  • ))}


);
};
```

**What you did**:
When entering Japanese (or any IME language) into a combobox that controls inputValue, IME composition fails.
This first screenshot renders a dropdown with `inputValue` controlled. I clicked the input to focus it and then typed "j" + "a".
Screen Shot 2022-12-09 at 11 45 05 AM

**What happened**:
The IME editor failed to open to further compose the characters before committing them. What I should have saw would have been this:
Screen Shot 2022-12-09 at 11 45 50 AM
Additionally, it appears that the `compositionend` event is never fired when inputValue is controlled.

**Problem description**:
When useCombobox is controlling `inputValue` and updating it with `onInputValueChange`, IME composition exits before showing the composition editor.

**Suggested solution**:
Wrap getInputProps's onChange handler with the spirit of the following:
```tsx
const onComposition = useRef(false);
const getOnChangeWithCompositionSupport = useCallback(
({
onChangeProp,
}: {
onChangeProp: (e: ChangeEvent) => void;
}) =>
(event: ChangeEvent) => {
setInputValue(event?.target?.value);

// IME method start
if (event.type === 'compositionstart') {
onComposition.current = true;
return;
}

// IME method end
if (event.type === 'compositionend') {
onComposition.current = false;
}

// handle parent onChange
if (!onComposition.current) {
onChangeProp?.(event);
}
},
[setInputValue]
);
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.