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

[Autocomplete] Add option to disable handling of home/end #19500

Closed
1 task done
mvestergaard opened this issue Jan 31, 2020 · 13 comments · Fixed by #20910
Closed
1 task done

[Autocomplete] Add option to disable handling of home/end #19500

mvestergaard opened this issue Jan 31, 2020 · 13 comments · Fixed by #20910
Labels
component: autocomplete This is the name of the generic UI component, not the React module! new feature New feature or request ready to take Help wanted. Guidance available. There is a high chance the change will be accepted

Comments

@mvestergaard
Copy link
Contributor

mvestergaard commented Jan 31, 2020

  • I have searched the issues of this repository and believe that this is not a duplicate.

Summary 💡

This is merely a suggestion, which I want to gauge the response to.
In some cases, it is not very nice that home/end navigates the options, rather than allowing navigation of the input field. For example, my use case it to use Autocomplete as the basis for a search field.

#18338 fixed a bug where you couldn't use home/end even when the popup isn't open, but what I'm suggesting goes further than that. It would be to add an option that disables the handling of home/end always.

Examples 🌈

N/A

Motivation 🔦

While typing in the field, you may want to quickly start over. For many users clearOnEscape isn't the most intuitive for that. I personally tend to do shift+home and then start typing again.

Or perhaps a new option isn't even needed, and it should just ignore home/end/up/down when shift is being held?

@oliviertassinari oliviertassinari added the component: autocomplete This is the name of the generic UI component, not the React module! label Jan 31, 2020
@oliviertassinari
Copy link
Member

oliviertassinari commented Jan 31, 2020

The current behavior originates from the recommendations of WAI-ARIA authoring practices. However, they make it optional:

Home (Optional): Either moves focus to and selects the first option or returns focus to the textbox and places the cursor on the first character.
End (Optional): Either moves focus to the last option or returns focus to the textbox and places the cursor after the last character.

https://www.w3.org/TR/wai-aria-practices-1.1/#listbox-popup-keyboard-interaction.

So I would suggest

  1. Let's use what the WAI-ARIA's examples are using as the default behavior.
  2. Let's make sure this behavior can be customized.

@mvestergaard
Copy link
Contributor Author

If one were to add an option to control this behavior, what would one call such a thing? All of my ideas feel rather verbose. disableHomeEndKeyboardHandling ugh...

But as to the last line i wrote above. Couldn't you kinda assume that if the shift key is being held, keypresses of home/end/up/down should go to the input field?

@oliviertassinari
Copy link
Member

oliviertassinari commented Jan 31, 2020

Well, it doesn't have to necessarily be a prop. For instance, it could be a keyboard event handler that set event.muiHandled = true.

@mvestergaard
Copy link
Contributor Author

Right, that could work too. I guess for now I'll handle it in a custom onKeyDown handler, and control which calls are propagated to useAutocomplete. It just feels a bit like a low level concern, that would be nice to handle in a more generic fashion.

@eps1lon
Copy link
Member

eps1lon commented Feb 1, 2020

Well, it doesn't have to necessarily be a prop. For instance, it could be a keyboard event handler that set event.muiHandled = true.

That's a misleading name. We specifically want to tell the component to not handle it. We can't use preventDefault either since we can't "unprevent" it in the autocomplete i.e. prevenDefault would also prevent the default of the textbox. Setting properties on the object is also not a good idea since have to persist the event. Seems like a prop is the best solution here.

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 1, 2020

Here is a prior-work with the event flag approach.

https://github.com/mui-org/material-ui/blob/83fb7f42ef47b68976e2856e26f074a974ba08f3/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js#L411-L414

A user could listen to the event before the component, flag the event as already handled so the component can ignore it. However, it's only one of the options available, it might not be the best one.

@oliviertassinari oliviertassinari added the waiting for 👍 Waiting for upvotes label Feb 22, 2020
@oliviertassinari
Copy link
Member

I have added the waiting for users upvotes tag. I'm closing the issue until we get more traction for it. So please upvote this issue if you are. We will prioritize our effort based on the number of upvotes.

@marcosvega91
Copy link
Contributor

What do you think about this implementation ?

index 2c33f552c..107820faf 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
@@ -1,5 +1,10 @@
 import * as React from 'react';
 
+
+export interface KeyDownOrder {
+  [key: string]: KeyDownOrderEvent[],
+}
+
 export interface CreateFilterOptionsConfig<T> {
   ignoreAccents?: boolean;
   ignoreCase?: boolean;
@@ -198,8 +203,20 @@ export interface UseAutocompleteCommonProps<T> {
    * It helps the user clear the selected value.
    */
   selectOnFocus?: boolean;
+  /**
+   * It establish the execution order of key-down events.
+   * For every key name you can pass an array with no more than two values.
+   * If the array is empty the event is skipped,
+   * Otherwise the events callback are fired following the order.
+   * If you want you can manage the event by your own by simple pass 'own' in the array
+   *
+   * @param {object} execution order of key down event
+   */
+  keyDownOrder?: KeyDownOrder
 }
 
+export type KeyDownOrderEvent = "default" | "own";
+
 export type AutocompleteHighlightChangeReason = 'keyboard' | 'mouse' | 'auto';
 
 export type AutocompleteChangeReason =

@oliviertassinari
Copy link
Member

oliviertassinari commented Apr 26, 2020

I came back to the use case of @mvestergaard, we have recently better organized the documentation to split the freeSolo use case into two different cases: 1. search field and 2. combobox create option. The discussion here was interesting because could further help differentiate the two use cases. I have tried to benchmark more, it seems very rare to have the wai-aria behavior implemented for Home and End on a search box, for instance, Google search doesn't, isn't it the most widely used search bar?

@marcosvega91 I don't understand what I'm looking at. Why does it concern the filtering?

@oliviertassinari
Copy link
Member

oliviertassinari commented Apr 26, 2020

Ok, my bad, the issue is that Material-UI prevent default the native behavior when freeSolo is true and the popup is open. It doesn't behave like Google search.

@oliviertassinari
Copy link
Member

We very likely need to make a change to account for it, it breaks the default behavior. We could either continue in the direction we have started with selectOnFocus and clearOnBlur, add a third handleHomeEndKeys like prop. This prop would be disabled by default if props.freeSolo.

The alternative is to say, 3 cases are enough, let's wrap all these concerns into a dedicated abstraction. I don't know, I think that I'm more in favor of handleHomeEndKeys, it's more flexible.

@oliviertassinari oliviertassinari added ready to take Help wanted. Guidance available. There is a high chance the change will be accepted and removed waiting for 👍 Waiting for upvotes labels Apr 26, 2020
@marcosvega91
Copy link
Contributor

I was referencing to this issue and #19887
My idea is to add a way for the user to decide the order of the event.
For example i can

<Autocomplete keyDownOrder={{"home":["own"]}} />

And when the keydown is pressed with home key only the onKeyDown callback passed by the user is fired.

I can

<Autocomplete keyDownOrder={{"home":[]}} />

In this case no callback is fired.

Or
<Autocomplete keyDownOrder={{"home":["own","original"]}} />

In this case the callback passed by the user is fired before the original ones.

I don't know if it makes sense

@oliviertassinari
Copy link
Member

@marcosvega91 Ok, let's move to #19887. For this one, I think that we have a compelling motivation to make a dedicated prop for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: autocomplete This is the name of the generic UI component, not the React module! new feature New feature or request ready to take Help wanted. Guidance available. There is a high chance the change will be accepted
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants