Skip to content

Tabbing to select active option in <Select> #26876

Closed

Description

@veltman
  • 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>
  );
}

Activity

  1. cuibonobo commented on Sep 24, 2020

    @cuibonobo

    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.

  2. antonabramovich commented on Apr 26, 2021

    @antonabramovich

    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.

  3. Vlad160 commented on Oct 13, 2021

    @Vlad160

    Any comments on this?

  4. saikrishnabanda5 commented on Feb 1, 2022

    @saikrishnabanda5

    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?

  5. Ctrain16 commented on Mar 2, 2022

    @Ctrain16

    Would love to see this implemented.

  6. michelooliveira commented on Jun 18, 2022

    @michelooliveira

    So is this feature ever going to be supported?

  7. jaredthecoder commented on Feb 6, 2023

    @jaredthecoder

    Is there an update here?

  8. jaredthecoder commented on Apr 30, 2023

    @jaredthecoder

    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.

  9. jaredthecoder commented on Jul 30, 2023

    @jaredthecoder
  10. ZachAlanMueller commented on Aug 10, 2023

    @ZachAlanMueller

    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.

  11. ZachAlanMueller commented on Aug 11, 2023

    @ZachAlanMueller

    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.

  12. sixwinds commented on Sep 4, 2023

    @sixwinds
    Contributor

    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.

  13. bombillazo commented on May 2, 2024

    @bombillazo
    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... 😞

  14. asAmitShrivastava commented on May 23, 2024

    @asAmitShrivastava

    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);
        }
    };
    
  15. nathanlao commented on Oct 13, 2024

    @nathanlao
    Contributor

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

  16. bombillazo commented on Nov 7, 2024

    @bombillazo
    Contributor

    EPIC! Thanks

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions