Part 1: Build This Cool Dropdown Menu with React, React Router and CSS
Tags: react, javascript, css, tutorial
Published: 2020-09-21 09:54:04

| [Part 1](https://dev.to/cooljasonmelton/build-this-cool-dropdown-menu-with-react-react-router-and-css-39ln) |
| -------------------- | 
| [Part 2](https://dev.to/cooljasonmelton/part-2-build-this-cool-dropdown-menu-with-react-react-router-and-css-5094)| 

How about a little dropdown menu to throw in a tight area of your site? Or maybe use it as a simple navigation tool with your minimalistic layout? Maybe use this smaller menu when the screen shrinks to smaller size.

![dropdown demo](https://dev-to-uploads.s3.amazonaws.com/i/nglfi1orf9r3dc2q7vlc.gif)

> [the code on GitHub](https://github.com/cooljasonmelton/dropdown)

### Tutorial
##### Table of Contents
*Preliminary Junk
*Menu Component
*Menu CSS
*React Router
*Conclusion

#####Preliminary Junk
To get it going, I made a `create-react-app`, installed [React Router](https://reactrouter.com/web/guides/quick-start), deleted any unneeded default code, and set up a file structure that looks like this:

![file structure](https://dev-to-uploads.s3.amazonaws.com/i/yvzl49av9qe3te5otbqa.png)

#####Menu Component
`Menu.js` contains all the JavaScript and JSX for our dropdown.

There are essentially four parts:

1. A `useState` hook holding a boolean that dictates if the menu should open. I call this `openMenu`.

2. A function called `setClassNames()` which conditionally adds classes to the menu items. The CSS of the classes will animate the menu.

3. A function called `pushToRoute()` which employs React Router to render the correlated component to the clicked menu item.

4. The `Menu` component’s return JSX for rendering the structure and bringing together all the functionality.

```react
import React, {useState} from 'react';

// router
import { withRouter } from 'react-router-dom';

// styling
import './Menu.css';

const Menu = props => {
    // conditionally render dropdown affect based on this boolean
    const [openMenu, setOpenMenu] = useState(false)

    // parameter num corresponds to .open-# classes
    // is assigned when Menu clicked triggering animated dropdown
    const setClassNames = num => {
        const classArr = ["m-item"];
        if (openMenu) classArr.push(`open-${num}`)
        return classArr.join(' ')
    }

    // takes route string as parameter
    const pushToRoute = route => {
        props.history.push(route)
        setOpenMenu(false)
    }

    return (
        <div className="Menu">
            <div className={"m-item m-logo"}
                onClick={() => setOpenMenu(!openMenu)}>
                Menu
            </div>
            <div className={setClassNames(1)}
                onClick={() => pushToRoute("/dashboard")}>
                Dashboard
            </div>
            <div className={setClassNames(2)}
                onClick={() => pushToRoute("/settings")}>
                Settings
            </div>
            <div className={setClassNames(3)}
                onClick={() => pushToRoute("/")}>
                Sign out
            </div>
        </div>
  );
}

export default withRouter(Menu);

```

#####Menu CSS

![dropdown menu](https://dev-to-uploads.s3.amazonaws.com/i/h6nwgyc1jise7pihzk5t.png)

CSS does all the work to open the menu. There are five important parts.

1  The `.Menu` class is the most outer container. This layer needs `position: relative;`.

The individual menu items will have a `position: absolute;`, so they will render based on the nearest component with a `position`. The basis of position will be the outer div of the `Menu` component.

2  The `.m-item` class is applied to each individual menu item. They are absolutely positioned with an initial `top: 0;`. This will render all the items on top of each other at the top of the `.Menu` div.

I use `em` units for `width` and all the other properties so I can ensure the items will fit perfectly on top of each other and still be responsive (`em` units are relative to the font-size of the element).

For aesthetics, I give them a `background-color`, `box-shadow`, `padding`, `border-radius`, `font-size`, and `color`.

The `flexbox` properties center the text vertically and horizontally. `cursor` changes the style of the mouse pointer on the screen to show the user menu items are clickable. 

Finally, `transition` will animate changing properties applied by the `setClassNames()` function and CSS `:hover`.

```css
.Menu{
    position: relative;
    margin: 2em 3em;
}

.m-item{
    position: absolute;
    top: 0;
    
    width: 5.5em;
    background-color: #301A4B;
    box-shadow: 1px 2px 2px #301A4B;

    padding: 0.2em;
    
    border-radius: 1em;

    display: flex;
    align-items: center;
    justify-content: center;

    font-size: 1.5em;
    color: #EDFFEC;
    cursor: pointer;

    transition: 1s;
}
```

3  `.m-item:hover` adds a small border to the menu items on hover. The added 1 px of border causes the items to animate slightly giving them a little bit of life.

```css
.m-item:hover{
    border: 1px solid black;
}
```

4  `.m-logo` is a special class for the first menu item. The `z-index: 1;` brings this div to the top so all other divs can hide beneath it.

`z-index` has a default value of 0 so if only one item has it declared, 1 will be enough to bring it to the top of all else.


```css
.m-logo{
    z-index: 1;
}
```


5  A series of classes called `.open-1`, `.open-2`, and `.open-3` cause the animation of the drop down. These classes are applied via `setClassNames()` when the the top menu item is clicked.

On click, each item transitions to the new properties in their `open-#` class. Namely, they will move to the newly specified `top` and new `background-color`.

```css
.open-1{
    top: 1.8em;
    background-color: #9b5de5;
}
.open-2{
    top: 3.6em;
    background-color: #f15bb5;
}
.open-3{
    top: 5.4em;
    background-color: #00BBF9;
}
```

#####React Router
All the aesthetic aspects of the Menu component are set up at this point. What's left is to set up React Router so clicking on items navigates you to the correct component.

I wired this up in three steps:

1  The `App.js` file is the main run file for the whole project so this is where I set up the basic Router stuff.

I wrap App's return with `BrowserRouter` so the soon-to-be Routes will be available to all components contained.

I set up a `Switch` so that when one Route is rendered, the others will be disabled. Within, I define each specific Route needed for the project (these are set to `null` for the sake of demonstration).

The `Menu` component is placed outside the `Switch` so it will render whenever `App` is rendering. This makes it an efficient navigation tool, available on any screen of the app.

```react
import React from 'react';

// router
import { BrowserRouter, Route, Switch } from 'react-router-dom';

// styling
import './App.css';

// components
import Menu from './Menu/Menu';

const App = () => {
  return (
    <BrowserRouter>
      <div className="App">
        {/* dropdown menu */}
        <Menu/>
        {/* routes */}
        <Switch>
          <Route exact path="/settings" component={null} />
          <Route exact path="/dashboard" component={null} />
          <Route exact path="/" component={null} />
        </Switch>
      </div>
    </BrowserRouter>
  );
}

export default App;
```
2  In our Menu component, I import `withRouter` and wrap the Menu with it in the export statement.

```react
// router
import { withRouter } from 'react-router-dom';
```

```react
export default withRouter(Menu);
```

`withRouter` gives `Menu` props that will allow us to manipulate the `react-router-dom`. To access these, we give `Menu` a parameter of `props`.

```react
const Menu = props => {
```

3  Finally, I wrote the function `pushToRoute()` which takes a parameter string of a route and pushes our app to that route. Then, it closes the Menu by calling `setOpenMen(false)`.

```react
    // takes route string as parameter
    const pushToRoute = route => {
        props.history.push(route)
        setOpenMenu(false)
    }
```

The menu items call `pushToRoute()` onClick.
For example:

```react
   <div className={setClassNames(1)}
        onClick={() => pushToRoute("/dashboard")}>
        Dashboard
   </div>
```

#####Conclusion

I enjoyed creating this menu. It’s an efficient and easy to code tool that could help in a number of scenarios. I hope you find the concepts useful.

I love feedback. Got any suggestions? I’d be happy to add your knowledge to my own. Hit me up below or email me: `jason.melton2@gmail.com` if you got a reason to.

Best! Jason Melton.