javascriptreactjsradio-grouptabindex

Tab selection ignores all elements generated within loop in React


I have radio group in my application and this group builds based on array const genders = ["Male", "Female", "Neutral"];, when I press the Tab button focus falls at the first element only and goes further ignoring the rest of elements.

const { useState } = React;

const App = () => {
  const genders = ["male", "female", "netural"];
  return (
    <React.Fragment>
      <h1>Hello Example</h1>
      <div>
        {genders.map((gender) => (
          <div key={gender}>
            <div>
              <input tabIndex={0} type="radio" value={gender} />
              {gender}
            </div>
          </div>
        ))}
      </div>
    </React.Fragment>
  );
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

I have prepared working example and sahred it here: sandbox

I have tried to add tabIndex to parent and to input element, but it didn't work. When I add tabIndex={0} it selects parent element first and goes to the input element after clicking the Tab one more time, it is bad behaviour.

Please tell me how can it be fixed ?


Solution

  • Just add a name to your inputs.

    <input name={"gender-" + gender} type="radio" value={gender} />
    

    Full example:

    const App = () => {
      const genders = ["male", "female", "netural"];
      return (
        <React.Fragment>
          <h1>Hello Example</h1>
          <div>
            <p>
              Same name (and same group, only 1 selected) - select first element with TAB and use arrows up and down
              keys to navigate
            </p>
            {genders.map((gender) => (
              <div key={gender}>
                <div>
                  <input name={"gender"} type="radio" value={gender} />
                  {gender}
                </div>
              </div>
            ))}
          </div>
          <br />
          <div>
            <p>Different names (and group - you can select all of them) - use tab key to navigate</p>
            {genders.map((gender) => (
              <div key={gender}>
                <div>
                  <input name={"gender" + gender} type="radio" value={gender} />
                  {gender}
                </div>
              </div>
            ))}
          </div>
        </React.Fragment>
      );
    };
    
    ReactDOM.render(
        <App />,
        document.getElementById("root")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    Notes: https://stackoverflow.com/a/14322638/5767872

    Radio buttons with one name is like single control (like input or select), you can change it value with arrow keys, tab key moves focus to another control.

    (Thanks @t-j-crowder)