Doğacan Bilgili A software developer who is also into 3D Modeling/Animation.

Building a custom dropdown menu component for React

5 min read 1586

Update: Github repo for the source code is included.


This package features two custom dropdown menu components for ReactJS. Online demo Single-selection Multi-selection Single-selection searchable Multi-selection searchable npm install reactjs-dropdown-component –save Make sure that you inserted the following link tag between the tags inside /public/index.html of your react project. This is required for the FontAwesome component that the package depends on.

It’s true that adapting an existing component into your project might not always go as smoothly as you’d like when it comes to specific requirements and styling. In such cases, building your own component might be in your best interest, considering the time that might be spent on the adaptation process.

This article will walk you through an approach that I followed in my personal project to create a custom dropdown menu component in React.

Visual structure

Before diving into the technical stuff, let’s quickly look at the visual structure of the dropdown menu component and decide on the requirements.

Visual structure of a dropdown component

A dropdown menu consists of four basic components:

  • header wrapping
  • header title
  • list wrapping
  • list items

The corresponding HTML could look like this:

<div className="dd-wrapper">
  <div className="dd-header">
    <div className="dd-header-title"></div>
  <ul className="dd-list">
    <li className="dd-list-item"></li>
    <li className="dd-list-item"></li>
    <li className="dd-list-item"></li>
  • We need to be able to toggle the dd-list upon clicking on dd-header and close it when clicked outside the dd-wrapper
  • We need to populate the <li> tags automatically based on data
  • We need to be able to control the header title

Before we can start to meet these requirements, we must decide whether to use functional component or class component.

Functional component or class component?

Functional components became faster in the latest release of React 16.

However, it is not always possible to take advantage when you need the state definition either in the component or any of the component lifecycle hooks.

We made a custom demo for .
No really. Click here to check it out.

For this specific example, it is possible to implement without a state definition or lifecycle hooks, but deploying them makes things more tidy and straightforward.

Using a functional component would require passing some variables as props. When we interact with the dropdown menu, we would be changing these props. Changing parent component’s props from a child component requires passing functions from parent to child as props so that you can control the parent component’s state.

If you overdo it, things will get complicated quickly. So, there are always trade-offs that should be considered.

We are going to deploy a class component with state and lifecycle hooks, whereas we will also be using functions as props in order to control the parent state.

Component relations

A parent component holds single or multiple dropdown menus and since each dropdown menu has a unique content, we need to parameterize it by passing information as props.

Let’s assume we have a dropdown menu, where we select multiple locations.

Consider the following state variable inside the parent component:

  this.state = {
    location: [
          id: 0,
          title: 'New York',
          selected: false,
          key: 'location'
        id: 1,
        title: 'Dublin',
        selected: false,
        key: 'location'
        id: 2,
        title: 'California',
        selected: false,
        key: 'location'
        id: 3,
        title: 'Istanbul',
        selected: false,
        key: 'location'
        id: 4,
        title: 'Izmir',
        selected: false,
        key: 'location'
        id: 5,
        title: 'Oslo',
        selected: false,
        key: 'location'

We have a unique id to use with key prop of map method when populating the location array; a title for each item in the list; a boolean variable named selected in order to toggle the selected items in the list (in case of multiple selections in a dropdown menu) and a key variable.

Key variable comes in very handy for using with setState function. I will touch on that later.

Now let’s take a look at what we passed to Dropdown component as props so far and shape the component accordingly. Below you see the Dropdown component used in a parent component.

  title="Select location"

We have a title to show and an array of data.

Before editing the render() method, we need a component state definition.

  this.state = {
    listOpen: false,
    headerTitle: this.props.title

Here we have a listOpen boolean variable for toggling the menu list and a headerTitle, which is equal to title prop.

Below see the render() method for the current configuration along with toggleList() and handleClickOutside() methods for toggling the list and closing the list when clicked outside the dd-wrapper respectively.

Note that handleClickOutside() comes from a third party HOC (Higher order component) named react-onclickoutside.

Moreover, FontAwesome is a component wrapping the font-awesome icon library.

    listOpen: false
  this.setState(prevState => ({
    listOpen: !prevState.listOpen
  const{list} = this.props
  const{listOpen, headerTitle} = this.state
    <div className="dd-wrapper">
<div className="dd-header" onClick={() => this.toggleList()}>
        <div className="dd-header-title">{headerTitle}</div>
          ? <FontAwesome name="angle-up" size="2x"/>
          : <FontAwesome name="angle-down" size="2x"/>
{listOpen && <ul className="dd-list">
       { => (
         <li className="dd-list-item" key={} >{item.title}</li>

With a styling applied, we get the following results.

Notice that we also deployed listOpen for toggling the arrow icon up or down by using the conditional (ternary) operator.

Dropdown menu, closed and open

Controlling a parent state from a child

When you pass something as a prop to a child component, you can only use that data and cannot change it unless you deploy additional props.

Passing a function, which uses setState, as a prop enables you to control the other props.

What you are doing is basically calling a function, which is defined in the parent component, from your child component to trigger the setState, which changes the state that passed as a prop in the first place.

In the case of the dropdown menu, we need to be able to toggle the selected key for the corresponding object in the location state, when a list element is clicked.

Control function in the parent

Defining the following function in the parent component and passing it as a prop to a child component, which is the Dropdown component, would enable us to control the desired information in the desired state.

toggleSelected(id, key){
  let temp = this.state[key]
  temp[id].selected = !temp[id].selected
    [key]: temp

Notice that we have id and key parameters for the toggleSelected() function.

Remember that we defined a key/value pair named key for each object inside the location array, now it is time to utilize it.

By using the key, we can tell toggleSelected() function which state variable to change.

key = "location"
//These two refers to the same state variable
- this.state.location
- this.state[key]

Likewise, the id tells which object to refer to in the location array variable.

Time to pass it as a prop:

  title="Select location"

Call it inside the <li> tag:

<li className="dd-list-item" key={item.title} onClick={() => toggleItem(, item.key)}>{item.title} {item.selected && <FontAwesome name="check"/>}</li>

Also, notice that I have added an icon, depending on the value of item.selected, to indicate that the item is selected.

Multiple items selected in the list

Dynamic header title

One last thing I wanted to have was a dynamic header title which changes in accordance with the number of selected items.

All we need to do is count how many of the selected key/value pairs are true and then change the headerTitle state in the Dropdown component accordingly.

We should update the component state when the location prop changes. In order to do so, we need to listen to prop updates through a life-cycle hook.

static getDerivedStateFromProps() is what we need.

It is a new lifecycle hook replacing the old componentWillReceiveProps() method.

Since it is a static method, it has no access to this . That would deprive us of using this.setState and this.props .

With this new method, you either return null to indicate that there is no change or you directly return the state modification. Also, since you have no access to this.props due to static method, you should store the previous props in a state and then reach them through prevState .

static getDerivedStateFromProps(nextProps, prevState)

We need to pass one more prop to Dropdown component to use for controlling the header title.

  title="Select location"

static getDerivedStateFromProps(nextProps){
    const count = nextProps.list.filter(function(a) { return a.selected; }).length;

if(count === 0){
      return {headerTitle: nextProps.title}
    else if(count === 1){
      return {headerTitle: `${count} ${nextProps.titleHelper}`}
    else if(count > 1){
      return {headerTitle: `${count} ${nextProps.titleHelper}s`}

The header title changes in accordance with the number of selected items in the list is shown below:

Dynamic header title


With my approach towards implementing a dropdown menu component for one of my projects, I basically kept the dropdown menu content data in the wrapping parent component and passed it as a prop. Passing a function also as a prop was the trick to control the parent state, which was eventually the data used in the Dropdown component.

Using static getDerivedStateFromProps() helped controlling the header title based on interaction with the dropdown menu.

You come here a lot! We hope you enjoy the LogRocket blog. Could you fill out a survey about what you want us to write about?

    Which of these topics are you most interested in?
    ReactVueAngularNew frameworks
    Do you spend a lot of time reproducing errors in your apps?
    Which, if any, do you think would help you reproduce errors more effectively?
    A solution to see exactly what a user did to trigger an errorProactive monitoring which automatically surfaces issuesHaving a support team triage issues more efficiently
    Thanks! Interested to hear how LogRocket can improve your bug fixing processes? Leave your email:

    Full visibility into production React apps

    Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

    LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

    The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

    Modernize how you debug your React apps — .

    Doğacan Bilgili A software developer who is also into 3D Modeling/Animation.

    9 Replies to “Building a custom dropdown menu component for React”

    1. The code snippets are not accurate. I tried following along but your syntax errors were too confusing to try to fix. Look at the portion where you introduce FontAwesome for random angle brackets and closing divs with no opens.

      1. Hi, Alex. Should be all set now. This isn’t Doğacan’s mistake. The formatting got borked when we migrated the blog to wordpress. Thanks for pointing it out (and sorry for the hassle).

    2. This tutorial is not bad (you can actually use functions with hooks and avoid using classes), but without the styles for the components I can’t really see the example that you produce here. So I would add a codepen or something with the whole component.

    3. Hey Dani,
      That’s true that now you can do that with hooks, but that was not an option back then when this tutorial was written.
      As for the styling, you can actually find the complete source code in the GitHub repo which I linked at the very beginning of this article.

    4. Im not sure how useful this tutorial is as I did not try it 🙂 But just by looking the code, I saw that it is not working as it should. A custom select should be accessible through a keyboard, like html select is, for accessibility reasons and for you to be able to select an option from your keyboard.
      So this tutorial has these things wrong:
      – No `role=”option”` and `role=”listbox”` attributes were set
      – There are no handlers for simulating a default’s “select” behavior, like navigating with the arrows.
      – It’s inaccessible

    5. I was about to start reading the tutorial, when I come across your review I changed my mind. thank you Mr. You are a time saver 😉

    6. I got an error “toggleItem is not defined” when I passed the toggle item to the list item.
      Please I need and urgent help.

    Leave a Reply