React - onClick does not work with option tag?

I’m raising a click event to a dropdown list controlled component, but the click event is not working. The component looks like this:

const Dropdown = props => {
  const { items, onItemSelect, textProperty, valueProperty } = props;

  return (
    <React.Fragment>
      <label htmlFor="genres">Genres</label>
      <select id="genres" className="dropdown">
        <option>Filter by genres...</option>
        {items.map(item => (
          <option
            key={item[valueProperty]}
            className="dropdown__option"
            onClick={() => onItemSelect(item)}
          >
            {item[textProperty]}
          </option>
        ))}
      </select>
    </React.Fragment>
  );
};

Dropdown.defaultProps = {
  textProperty: "name",
  valueProperty: "id"
};

The state component (which is the main component of the whole app):

handleGenreSelect = genre => {
    console.log(genre);
  };

render() {
  <div className="container">
    <SideBar items={this.state.genres} onItemSelect={this.handleGenreSelect} />
  </div>
}

As you can see above, I’m passing the data to the Dropdown component through another controlled component:

const SideBar = props => {
  const { items, onItemSelect } = props;
  return (
    <nav className="sidebar">
      <ul className="side-nav">
        <li className="side-nav__item side-nav__item--active">
          <span className="side-nav__span">Popularity</span>
        </li>
        <li className="side-nav__item">
          <span className="side-nav__span">Release date</span>
        </li>
        <li className="side-nav__item">
          <span className="side-nav__span">
            <Dropdown onItemSelect={onItemSelect} items={items} />
          </span>
        </li>
      </ul>
    </nav>
  );
};

What am I missing here?

Hi Gilbert!

Your handler should be on your select element, not on the option elements.
Try adding an onChange handler on your select element and reference the selected dropdown item on the events target.value property in your handler.

1 Like

Thanks for replying, onChange does work on the select tag, but I need this event to be on the option tags, because I’m creating a list of option dynamically to list all the genres of my genres array of objects.

It seems I can’t use onClick or onChange on a <option> tag?

Also keep in mind when you add an Event the scope change so you have to add a bind to change the scope.

Hi @Gilbert1391

Did you test out my suggestion? The event object that is passed to your onChange handler should give you the value of the selected option (via event.target.value) when onChange is triggered if you attach it to the select element. It does not matter if your list of options is dynamic, it will apply to the options you have at the time your event handler is triggered.

I tested this against a slight modification of your code and it worked fine, but maybe I’m not fully understanding your question.

Hey @cmccormack

I ended up with another structure, I found out you can’t have event listener on <option></option> tags, if you want to read the value of the selected option element you have to add the event to the <select></select> tag with event.target.value, however this approach wouldn’t do it for me as I was not trying to get the value but the object itself. Besides, <option></option> tags are hard to style, so I used <li></li> elements instead, much easier.

Honestly I would like to create a custom and reusable dropdown component w/o using the <option> tags. I’ve seen some libraries use <div> and/or <li>, I would like to know how they do it so I can create one myself.

Can you describe what you mean? We can possibly help but need a better understanding.

Thanks!

Basically I was rendering a list of <option></option> tags dynamically by mapping an array of objects.

const genres = [
 { id: 1, genre: "Action" },
 { id: 2, genre: "Horror" },
 { id: 3, genre: "Comedy" }
];
handleGenreSelect = genre => {
 console.log(genre)
};

<select>
 {genres.map(el => <option key={el.id}>{el.genre}</option>)}
</select>

So instead of reading the value of the option tags, I wanted to get the object created dynamically with the map method.

If by object you mean the HTML element, you will get that reference from event.target if you put the handler on the select element.

Check out this example and let me know if it’s what you’re trying to do.
It displays the target value in the DOM as well as the HTML element in the console.

2 Likes

Thank you so much :heart:@cmccormack

1 Like

It worked for my requirement. Thank you @cmccormack
If any one wants to know how onChange event works on tag please refer this link from MDN
HTMLElement-change_event