-
Notifications
You must be signed in to change notification settings - Fork 355
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
feat(Select/Dropdown/MenuContainer): arrow key handling to focus items #11132
feat(Select/Dropdown/MenuContainer): arrow key handling to focus items #11132
Conversation
Preview: https://patternfly-react-pr-11132.surge.sh A11y report: https://patternfly-react-pr-11132-a11y.surge.sh |
c036179
to
fd712a7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential problem: if consumers pass a component prop to MenuItem other than button / input / a, it won't focus the item. They can always override the onArrowUpDownKeyDown themselves, but I am wondering whether we should provide some prop to specify, what is the html element they want to focus.
Yeah, this is something that was in the back of my mind. Allowing a consumer to customize the query string for elements that can be possibly focused (either auto on open, or via this arrow key handler). Adding a prop for that might require tweaking either the auto-focus logic or this, though, since the default query strings are just slightly different (querying a string that includes "li" for each query vs querying within an already captured <li>
element).
I think the question then is if it makes sense to have both a callback to customize onKeydown handling for the arrow keys, and a prop to customize the query string. Via a query string a consumer could try to focus anything that's inside the menu (but not in the actual menu list, e.g. a menu with search filter).
It probably doesn't hurt to have both; maybe the a prop for a custom query string could be a more "basic" customization, and this callback prop could be a more "advanced" customization. cc @tlabaj wdyt?
@thatblindgeye Can the query string be an argument of the callback with the default being |
@tlabaj so with this addition, we would have 2 instances where we're attempting to get an element to focus via a querySelector string: once for the automatic focusing when If we were to implement a query string prop, at that point I was just wondering if this custom callback prop would be as useful, or if we should only run our default logic for when Up/Down arrow is pressed without the ability to customize. Within Select and Dropdown, the query string should be capturing anything within Like I said it doesn't really hurt to have both. A query string prop is a bit simpler of a customization, whereas this callback prop could provide even more fine tuned control. I'm thinking more whether 2 props would be necessary immediately or if we should try just adding 1 and seeing what consumers think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query selector is only looking at the first and last li
currently, so this behavior breaks if the first/last option is disabled. To skip disabled options, a single querySelectorAll('li button:not(:disabled),input:not(:disabled),a:not([aria-disabled="true"])')
call instead of looking for the li
separately should work, and then we'd grab the first/last of that resulting array.
To your question at the top, I think it's fine to not have a direct prop to customize the focusable element. The user can override the toggle keydown behavior, and has access to the menu ref to do their own query. I'd prefer to try to keep the API streamlined, and we can always add a prop for it later down the line if we get requests for it.
@@ -51,6 +51,8 @@ export interface DropdownProps extends MenuProps, OUIAProps { | |||
onOpenChange?: (isOpen: boolean) => void; | |||
/** Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable. */ | |||
onOpenChangeKeys?: string[]; | |||
/** Callback to override the default behavior when pressing up/down arrow keys when the toggle has focus and the menu is open. By default non-disabled menu items will receive focus - the first item on arrow down or the last item on arrow up. */ | |||
onToggleArrowKeydown?: (event: KeyboardEvent) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this prop can be generalized to onToggleKeydown
since it could be used to add any key behavior.
The description could also be updated to Callback to override the toggle keydown behavior. By default, when the toggle has focus and the menu is open, pressing the up/down arrow keys will focus a valid non-disabled menu item - the first item for the down arrow key and last item for the up arrow key.
The double when
is slightly confusing to me.
Same goes for MenuContainer
and Select
.
/** Callback to override the default behavior when pressing up/down arrow keys when the toggle has focus and the menu is open. By default non-disabled menu items will receive focus - the first item on arrow down or the last item on arrow up. */ | ||
onToggleArrowKeydown?: (event: KeyboardEvent) => void; | ||
/** Indicates that the Select is used as a typeahead (combobox). Focus won't shift to menu items when pressing up/down arrows. */ | ||
isTypeahead?: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any chance we would want this to be a wider covering variant
prop? Ideally we don't want to have this prop and later find we need to also add isCheckbox
, isMultiTypeahead
, etc. If we go with variant
, the prop description can indicate that the prop affects default keyboard behavior based on its value.
What does everyone think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good to me
@thatblindgeye in response to the prop conversation above. I understand now and the prop is fine. Like Katie said, we can add an argument to callback at a later time if it is requested. |
I had to keep the querySelector looking for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated behavior lgtm. Only open question left is if we want to leave the isTypeahead
prop as is or rename it to variant
. I don't think that's blocking though and we can update it later if necessary in the next breaking change release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Tested with the Talon program for voice input and saying "Arrow Up/Down" focuses things as expected nicely.
We should ideally have a followup where we show a more custom callback being used, possibly justupdating the custom inline filter menu example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm another than changing the isTypeahead
prop to `variant. Like Katie said, it allows for further expansion later on. Not a blocker for me though.
@thatblindgeye @kmcfaul this would be good to get into v5 correct? It could help with adoption... |
@tlabaj yeah most likely since we reversed the default value of that autofocus prop there, too. |
@adamviktora can you open a PR for the same fix in v5 please. |
Your changes have been released in:
Thanks for your contribution! 🎉 |
Closes #11131
Potential problem: if consumers pass a
component
prop to MenuItem other thanbutton
/input
/a
, it won't focus the item. They can always override theonArrowUpDownKeyDown
themselves, but I am wondering whether we should provide some prop to specify, what is the html element they want to focus.