-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Add focusDefaultOption prop to prevent focusing first option #4080
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
base: master
Are you sure you want to change the base?
Changes from all commits
e5b7fc2
45f4d54
0e42b3a
581beaa
b3491db
6c1b768
1b6c972
626f1c4
261ad14
5467d70
5d1cf66
ee35360
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import React from 'react'; | ||
| import Select from 'react-select'; | ||
|
|
||
| import { colourOptions } from '../data'; | ||
|
|
||
| const DisableDefaultFocus = () => ( | ||
| <Select | ||
| options={colourOptions} | ||
| focusDefaultOption={false} | ||
| /> | ||
| ); | ||
|
|
||
| export default DisableDefaultFocus; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,8 @@ export type Props = { | |
| formatGroupLabel: typeof formatGroupLabel, | ||
| /* Formats option labels in the menu and control as React components */ | ||
| formatOptionLabel?: (OptionType, FormatOptionLabelMeta) => Node, | ||
| /* Applies focus to the first option in the menu when opened */ | ||
| focusDefaultOption: boolean, | ||
| /* Resolves option data to a string to be displayed as the label by components */ | ||
| getOptionLabel: typeof getOptionLabel, | ||
| /* Resolves option data to a string to compare options and specify value attributes */ | ||
|
|
@@ -258,6 +260,7 @@ export const defaultProps = { | |
| escapeClearsValue: false, | ||
| filterOption: createFilter(), | ||
| formatGroupLabel: formatGroupLabel, | ||
| focusDefaultOption: true, | ||
| getOptionLabel: getOptionLabel, | ||
| getOptionValue: getOptionValue, | ||
| isDisabled: false, | ||
|
|
@@ -415,9 +418,21 @@ export default class Select extends Component<Props, State> { | |
| const menuOptions = nextProps.menuIsOpen | ||
| ? this.buildMenuOptions(nextProps, selectValue) | ||
| : { render: [], focusable: [] }; | ||
| const focusedValue = this.getNextFocusedValue(selectValue); | ||
| const focusedOption = this.getNextFocusedOption(menuOptions.focusable); | ||
| this.setState({ menuOptions, selectValue, focusedOption, focusedValue }); | ||
|
|
||
| let focusedValue = null; | ||
| let focusedOption = null; | ||
|
|
||
| if (nextProps.focusDefaultOption) { | ||
| focusedValue = this.getNextFocusedValue(selectValue); | ||
| focusedOption = this.getNextFocusedOption(menuOptions.focusable); | ||
| } | ||
|
Comment on lines
+425
to
+428
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that this prop should affect
Comment on lines
+422
to
+428
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A cleaner way to do this would be to check There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And actually, now that I think it about, this logic is incorrect if we don't move it into The situation where this would make a difference is if the menu is open and the So instead we should change to: |
||
|
|
||
| this.setState({ | ||
| menuOptions, | ||
| selectValue, | ||
| focusedOption, | ||
| focusedValue, | ||
| }); | ||
| } | ||
| // some updates should toggle the state of the input visibility | ||
| if (this.inputIsHiddenAfterUpdate != null) { | ||
|
|
@@ -498,7 +513,7 @@ export default class Select extends Component<Props, State> { | |
| openMenu(focusOption: 'first' | 'last') { | ||
| const { selectValue, isFocused } = this.state; | ||
| const menuOptions = this.buildMenuOptions(this.props, selectValue); | ||
| const { isMulti } = this.props; | ||
| const { isMulti, focusDefaultOption } = this.props; | ||
| let openAtIndex = | ||
| focusOption === 'first' ? 0 : menuOptions.focusable.length - 1; | ||
|
|
||
|
|
@@ -516,7 +531,7 @@ export default class Select extends Component<Props, State> { | |
| this.setState({ | ||
| menuOptions, | ||
| focusedValue: null, | ||
| focusedOption: menuOptions.focusable[openAtIndex], | ||
| focusedOption: focusDefaultOption ? menuOptions.focusable[openAtIndex] : null, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might have the interesting effect of calling I believe we can remove the second case because there is not a time where we call |
||
| }, () => { | ||
| this.onMenuOpen(); | ||
| this.announceAriaLiveContext({ event: 'menu' }); | ||
|
|
||
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.
nit and bike shedding: I prefer
autoFocusOptionorautoFocusFirstOptionas the prop name, but that's just a personal preference.autoFocusvsfocus: in my mind reinforces that this is something that happens once when the menu opens, but that the focus can change with user input.optionorfirstOptionvsdefaultOption:defaultOptionmakes it sound like to me that the the default option is something that is customizable when it's not. Usingoptionstill leaves room for future props that could change whichoptionis focused by default, but that's not the case at the moment.But I'm fine with
focusDefaultOptionif that's easier.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.
Hmmm I thought
autoFocuswould be like input#autofocus where the field snatches a user's focus.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.
Yeah, there's a little bit of overloading with the word "focus" which makes it hard to differentiate, since we have to talk about both focus of the Select component and the focus of individual options when the menu is open.
I think maybe the most descriptive (but probably too long) prop name would be
autoFocusFirstOptionOnMenuOpenwhere theonMenuOpendisambiguates when the auto-focusing would happen.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.
Knowing the full context, I prefer your
autoFocusOption; however, could we not change the type signature to allow people to choose a different item to receive first focus? Who's to say maybe somebody would not want to focus the last option, or some middle one 🤷 . Regardless, I like that naming best. If it will be constrained to just boolean, I like your longer variable name:autoFocusFirstOptionOnMenuOpen- very crystal clear.Uh oh!
There was an error while loading. Please reload this page.
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.
Yeah, it's hard to know where to stop as far as customization. Our options ordered from most customizable to least customizable are:
getDefaultFocusedOptionprop which is a function where the user is passed information and they can return the option they want to be focused by default.autoFocusOptiona prop that can be'first' | 'last' | false(can be expanded later, but I'm not sure what else you would need).autoFocusOptiona prop that can betrueorfalse.Since
react-selectis already very complex and hard to keep straight with all its edge cases, I think we want to be conservative and avoid complexities.That's why I suggested
autoFocusOptioninstead ofautoFocusFirstOptionas my top choice (if we go withtrue | false) because it leaves open the possibility of adding'first' | 'last'options later on.But you make a good point. Maybe
autoFocusOptionOnMenuOpenis the best of both worlds because it avoids usingfirstso that we can expand it later and is very clear.