Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combobox completely broken on Android chrome on the latest version #2575

Closed
travelarrow opened this issue Jul 4, 2023 · 6 comments · Fixed by #2580
Closed

Combobox completely broken on Android chrome on the latest version #2575

travelarrow opened this issue Jul 4, 2023 · 6 comments · Fixed by #2580
Assignees

Comments

@travelarrow
Copy link

1.7.15

@headlessui/react

Android Chrome

The combobox component is COMPLETELY broken on the latest headlessui react version. When you type on the keyboard, the onChange event does not fire. We had to downgrade to previous version to make it work. This is a critical site breaking issue that completely broke our site for 2 weeks.

@RobinMalfait RobinMalfait self-assigned this Jul 5, 2023
@RobinMalfait
Copy link
Member

RobinMalfait commented Jul 5, 2023

Hey, thank you for this bug report, and sorry about the Combobox being unusable for you. Let's see if we can help you out here.

Can you tell me a bit more about what you mean that it is completely broken? That we can gather some information and find a solution for the issues you are having. The latest release should not contain any breaking changes from an API perspective.

  • Do you see any errors in the console?
  • When typing, is there no text at all?
    • Or is it delayed by a lot (aka slow / performance issue)?
  • Is the Combobox itself not opening once you type?
  • Are the options not being filtered when you type?
  • Can you open the Combobox using the Combobox.Button?
  • If you can open the Combobox somehow, does selecting an item work?
    • Does it work using the mouse?
    • Does it work using the keyboard?
  • Can you share a minimal reproduction repo that shows the issue you are having? (Either a repo or a CodeSandbox or similar)

I just tried to reproduce this using this example (https://headlessui-react.vercel.app/combobox/combobox-with-pure-tailwind) on an older Android (Nexus 6P from ~2015, Android 8.1.0) device using Chrome (114.0.5735.196) and this is what I see:

Screen.Recording.2023-07-05.at.11.36.38.mov

@JarrodLodge
Copy link

I'm experiencing the same issue as well. It looks like the onchange event is not firing on android anymore.
Work around is that the back button seems to trigger the list items to load. And once it loads it seems to work as intended.

This is using Vue 3. headlessui/vue: 1.7.13

Text.input.example.mp4

@RobinMalfait
Copy link
Member

Thanks for the video @JarrodLodge, I see what you mean now.

/cc @thecrypticace when you type on Android you are always in a composition mode until you press enter or space... because they are using the IME APIs for entering text. That's also why I think the text in the video is using an underline.

I have a fix incoming!

RobinMalfait added a commit that referenced this issue Jul 6, 2023
We had an issue #2409 where typing using an IME (Input Method Editor,
E.g.: Japanese — Romaji) already submitted characters while the user was
still composing the characters together.

1. Type `wa`
2. Expected result: `わ`
3. Actual result: `wあ` (where `あ` is the character `a`)

This was solved by not triggering change events at all until the
`compositionend` event was triggered. This worked fine for this use
case. However this also meant that only at the end of your typing
session (when you press `enter`/`space`) the actual value was submitted.

Fast forward to today, we received a new issue #2575 where this
behaviour completely broke on Android devices. Android _always_ use the
IME APIs for handling input... if we think about our solution form
above, it also means that while you are typing on an Android device no
options are being filtered at all. The moment you hit enter/space the
combobox will open and results will be filtered.

This is where this fix comes in. The goals are simple:

1. Make it work
2. Try to make the current code simpler

I started digging to see _why_ this `wあ` was even submitted. A normal
input field doesn't do that?! We have some code that does the following
things:

1. Sync the selected value with the `input` such that if you update the
   value from the outside, then the value in the `input` is up-to-date
   with the `displayValue` of that incoming value.
2. A fix for macOS VoiceOver to improve the VoiceOver experience when
   opening the `Combobox` component. This is done by manually resetting
   the value of the `input` field.

   1. Keep track of the current value
   2. Keep track of the current selection range (start/end) state
   3. Reset the input to an empty string `''`
   4. Restore the value to the captured value
   5. Restore the selection range

When you are typing, the input field doesn't have to update yet because
typing doesn't cause an option to become the `selected` option,
therefore it doesn't have to sync the value yet. So (1.) isn't the issue
here.

However, when you start typing, the Combobox should open and then we
trigger the macOS VoiceOver fix. This is touching the `input` field
because we change the value & selection.

Because we touched the `input` while the user was still in a composing
mode, it bailed and submitted whatever characters it had. This is the
part that we don't want. Not applying the macOS VoiceOver fix while
typing solves this issue. In addition, because _we_ are touching the
input field, VoiceOver is acting normally.

In hindsight, the solution is very simple: do not touch the input field
when the user is typing.

We still keep track whether the user `isComposing` so that we can bail
on the default `Enter` behaviour (marking the current option as the
selected option) because pressing `Enter` while composing should get out
of the IME.

Fixes: #2575
@RobinMalfait
Copy link
Member

@travelarrow can you confirm that the issue you see is the same issue as @JarrodLodge is showing?

@RobinMalfait
Copy link
Member

Alright here is what I'm going to do:

I know that there are bugs that #2580 solves. So I'm going to merge this and get a release out either later today or by the end of the week (tomorrow).

Assuming this is the same issue, then we should be good. If not, then once there is more information available we will fix that in a separate PR.

RobinMalfait added a commit that referenced this issue Jul 6, 2023
* simplify `isComposing`

We had an issue #2409 where typing using an IME (Input Method Editor,
E.g.: Japanese — Romaji) already submitted characters while the user was
still composing the characters together.

1. Type `wa`
2. Expected result: `わ`
3. Actual result: `wあ` (where `あ` is the character `a`)

This was solved by not triggering change events at all until the
`compositionend` event was triggered. This worked fine for this use
case. However this also meant that only at the end of your typing
session (when you press `enter`/`space`) the actual value was submitted.

Fast forward to today, we received a new issue #2575 where this
behaviour completely broke on Android devices. Android _always_ use the
IME APIs for handling input... if we think about our solution form
above, it also means that while you are typing on an Android device no
options are being filtered at all. The moment you hit enter/space the
combobox will open and results will be filtered.

This is where this fix comes in. The goals are simple:

1. Make it work
2. Try to make the current code simpler

I started digging to see _why_ this `wあ` was even submitted. A normal
input field doesn't do that?! We have some code that does the following
things:

1. Sync the selected value with the `input` such that if you update the
   value from the outside, then the value in the `input` is up-to-date
   with the `displayValue` of that incoming value.
2. A fix for macOS VoiceOver to improve the VoiceOver experience when
   opening the `Combobox` component. This is done by manually resetting
   the value of the `input` field.

   1. Keep track of the current value
   2. Keep track of the current selection range (start/end) state
   3. Reset the input to an empty string `''`
   4. Restore the value to the captured value
   5. Restore the selection range

When you are typing, the input field doesn't have to update yet because
typing doesn't cause an option to become the `selected` option,
therefore it doesn't have to sync the value yet. So (1.) isn't the issue
here.

However, when you start typing, the Combobox should open and then we
trigger the macOS VoiceOver fix. This is touching the `input` field
because we change the value & selection.

Because we touched the `input` while the user was still in a composing
mode, it bailed and submitted whatever characters it had. This is the
part that we don't want. Not applying the macOS VoiceOver fix while
typing solves this issue. In addition, because _we_ are touching the
input field, VoiceOver is acting normally.

In hindsight, the solution is very simple: do not touch the input field
when the user is typing.

We still keep track whether the user `isComposing` so that we can bail
on the default `Enter` behaviour (marking the current option as the
selected option) because pressing `Enter` while composing should get out
of the IME.

Fixes: #2575

* update changelog
@RobinMalfait
Copy link
Member

This should hopefully be fixed by #2580, and will be available in the next release.

You can already try it using:

  • npm install @headlessui/react@insiders.
  • npm install @headlessui/vue@insiders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants