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

Tabbing to select active option in <Select> #26876

Closed
1 task done
veltman opened this issue Sep 23, 2020 · 16 comments · Fixed by react-component/select#1078 · May be fixed by react-component/select#974
Closed
1 task done

Tabbing to select active option in <Select> #26876

veltman opened this issue Sep 23, 2020 · 16 comments · Fixed by react-component/select#1078 · May be fixed by react-component/select#974

Comments

@veltman
Copy link

veltman commented Sep 23, 2020

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

What problem does this feature solve?

Currently, when using a focused Select component, if you use the keyboard to move down the list of options and hit Tab, it will blur the menu without selecting the active option. I think the preferred default would be that if the dropdown is open, hitting Tab selects the active option in addition to closing the menu (this is what react-select does, for example).

I also don't think there is a way for a user to implement this on their own, because there's no event triggered by changing the active option in an open dropdown menu.

What does the proposed API look like?

Select the active option on tabbing by default, without any public API change.

An alternative could be exposing an onActiveOptionChange event, so that someone could do something like:

function SelectWithTab({ value, handleChange }) {
  const [active, setActive] = useState(value);
  return (
    <Select
      value={value}
      onInputKeyDown={({ keyCode }) => {
          if (keyCode === 9) {
              handleChange(active);
        }
      }}
      onChange={handleChange}
      onActiveOptionChange={setActive}
    >
      <Option value="jack">Jack</Option>
      <Option value="lucy">Lucy</Option>
    </Select>
  );
}
@cuibonobo
Copy link

I would also like to see this! The current behavior is not consistent with the default HTML select and is an accessibility / muscle-memory issue.

@antonabramovich
Copy link

antonabramovich commented Apr 26, 2021

Adding my 2 cents here: both ARIA specification and <select> MDN page mention that highlighted option should be backfilled (just like in Antd autocomplete) when navigating with arrows.
Would be nice to have this feature.

@Vlad160
Copy link

Vlad160 commented Oct 13, 2021

Any comments on this?

@saikrishnabanda5
Copy link

How do i take the value when we are using key down and key up with select option . I have to capture the value when i am using down and up arrow in options?

@Ctrain16
Copy link

Ctrain16 commented Mar 2, 2022

Would love to see this implemented.

@michelooliveira
Copy link

So is this feature ever going to be supported?

@jaredthecoder
Copy link

Is there an update here?

@jaredthecoder
Copy link

Anything we can do to help @afc163? I would make a PR but I am not an expert in JS enough to do backend library updates.

@jaredthecoder
Copy link

@afc163?

@ZachAlanMueller
Copy link

I'm chiming in here because I am also experiencing this issue. There is no good way to implement what standard html-based selects do with antd Select, which is a shortcoming.

@ZachAlanMueller
Copy link

I've looked into this further, and it appears to be deliberately disabled functionality. Ant Design Select is a wrapper of rc-select, which has a 3rd mode, called combobox. This is a combination of searching and selecting, hence the combobox name. The mode combobox is disabled. (1)

Next, is the backfill option, that is a property of rc-select, that when you use up/down arrows, will set the current value of the select to the option you are 'hovering' over. This option is also disabled. (2) In the code snippet below, you can see they omit the property 'backfill'.

I'm not 100% sure, but I believe that if you enabled these 2 options and use them together, that we would get this lost functionality.

I'm pinging a few recent contributors to this repo, because I believe this is a necessary change, along with the fact that this issue is still marked inactive when I believe that has been done in error. (3)
@zombieJ @MadCcc @PeachScript

(1) Found in components\select\index.tsx
if (m === 'combobox') { return undefined; }

(2) Found in components\select\index.tsx
`
export interface SelectProps<
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,

extends Omit<
InternalSelectProps<ValueType, OptionType>,
'mode' | 'getInputElement' | 'getRawInputElement' | 'backfill' | 'placement'
{
...
}`

(3) Why is this change needed? This is a core functionality of standard html-only selects. There is a comment above going into more detail as well if further detail is needed.

@sixwinds
Copy link
Contributor

sixwinds commented Sep 4, 2023

I have a temp fall back implementation, the idea is that find the active option dom node when blur:

// libs
import { useRef } from 'react';
import { Select } from 'antd';
// utils
import isFunction from '@/utils/isFunction';

// this func is based on antd version 4, you can customized it on your antd version
const getActiveOpitonContentElement = (rootElement) => {
  if (rootElement) {
    const activeOptionElement = rootElement.getElementsByClassName(
      'ant-select-item-option-active',
    )?.[0];
    if (activeOptionElement) {
      const optionContentElement = activeOptionElement.getElementsByClassName(
        'ant-select-item-option-content',
      )?.[0];
      return optionContentElement;
    }
  }
  return void 0;
};

const MySelect = (props) => {
  const {
    options,
    optionFilterProp,
    dropdownRender,
    onBlur,
    onChange,
    ...restProps
  } = props;

  const dropdownWrapperElementRef = useRef();

  return (
    <Select
      {...restProps}
      onChange={onChange}
      optionFilterProp={optionFilterProp}
      options={options}
      dropdownRender={(originNode) => {
        if (isFunction(dropdownRender)) {
          return (
            <div ref={dropdownWrapperElementRef}>
              {dropdownRender(originNode)}
            </div>
          )
        }
        return (
          <div ref={dropdownWrapperElementRef}>
            {originNode}
          </div>
        );
      }}
      onBlur={(...args) => {
        // ---- [implementation of tabbing to select active option] start -----
        const activeOptionContentElement = getActiveOpitonContentElement(
          dropdownWrapperElementRef.current,
        );
        if (
          activeOptionContentElement &&
          Array.isArray(options) &&
          options.length > 0
        ) {
          const activeOption = options.find((el) => {
            return (
              el[optionFilterProp ?? 'value'] ===
              activeOptionContentElement.innerText
            );
          });
          if (activeOption && isFunction(onChange)) {
            onChange(activeOption.value);
          }
        }
        // ---- [implementation of tabbing to select active option] end -----

        if (isFunction(onBlur)) {
          onBlur(...args);
        }
      }}
    />
  );
};

It is based on antd version 4, but I think developer can customized the implementation.

@bombillazo
Copy link
Contributor

Hey, I also agree this is a very common UX approach, if one has moved the cursor or focused on a selection or is using search and a result is highlighted, one would expect that pressing tab would select to item. Instead, we need to press Enter or click on it to actually select then press Tab... 😞

@asAmitShrivastava
Copy link

I have tried an alternative way , please check this out :

const handleKeyDown = (event: any) => {
    if (event.key === 'Tab') {
        event.preventDefault();

        const enterEvent = new KeyboardEvent('keydown', {
            key: 'Enter',
            code: 'Enter',
            keyCode: 13,
            bubbles: true,
        });

        event.target.dispatchEvent(enterEvent);
    }
};

@nathanlao
Copy link
Contributor

Submitted a PR in rc component/select to handle the case that we can tab to select active option

@bombillazo
Copy link
Contributor

EPIC! Thanks

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