Creating a Context Menu for my Bookmark Manager
Tags: productivity, react, webdev, showdev
Published: 2020-11-04 15:32:38

Today I replaced the topbar entries of my bookmark manager called [Crumb Collector](https://www.crumb-collector.com) with a context menu, because they did not fit properly anymore on mobile devices. The app is written using the MERN stack, so in this post I'd like to share how I created this context menu in React.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2v1rr3261d9zvvfg2zce.gif)

_I also finally managed to properly loop the cover image GIF, but that's not the topic of this post._:wink:

## The Requirement

I used to have just the `Log In` button in the top right corner, but wanted to add a few more icons, which made it too wide for mobile devices. I wanted the context menu to open when the user hovers over it and it should include important links on the site as well as links to my blog, Twitter and Dev.to.

## The Basic Setup

The topbar is a `div`-element with fixed position, so that it is always at the top of the screen. I am using [FontAwesome](https://fontawesome.com/icons/caret-down?style=solid) for the caret icon. The `More` entry is the container for our context menu. The menu itself is placed outside of the viewport using `position: absolute` and `right: -10rem` and will be made visible when we hover over `More`.

I added a `transition-delay` to `.topbar-menu` so that it does not disappear immediately, when the mouse leaves the element that triggered the hover-effect.

**The JSX**

```
<div className='topbar'>
  <div className='topbar-items'>
    {handleDarkmode}
    <span className="more" >
      More <i className="fas fa-caret-down"></i>
        <ul className="topbar-menu">
          <li>...</li>
          <li>...</li>
        </ul>
    </span>
  </div>
</div>
```

**The CSS**

```
/* This is the topbar, pinned to the top.*/
.topbar {
  position: fixed;
  display: flex;
  flex-direction: row;
  height: 48px;
  width: 100%;
  background-color: #252525;
  line-height: 36px;
  z-index: 2;
  top: 0;
}

/* This is the class for the topbar items.*/
.topbar-items {
  display: flex;
  margin-left: auto;
  margin-right: 2rem;
  align-items: center;
  cursor: pointer;
  color: white;
}

/* This is the context menu, placed outside of the viewport 
 */
.topbar-menu {
  position: absolute;
  right: -10rem;
  margin-top: 0.8rem;
  background-color: #1c75da;
  display: flex;
  flex-direction: column;
  transition: 0.1s;
  transition-delay: 0.3s;
  text-align: center;
  width: auto;
  border-radius: 0.3rem;
  font-weight: 700;
}
```

## Displaying The Context Menu

I want the menu to show up automatically when I hover over `More`, so I have to add `:hover` to the menu entry in combination with class `.topbar-menu`. On hover, the menu will move into the viewport using `transform: translateX`.

```
.more:hover .topbar-menu {
  transform: translateX(-11rem);
  transition: 0.1s;
}
```

## Styling the menu

The first four items are just regular list-items that are styled like this:

**The JSX**

```
        <ul className="topbar-menu">
          <li className="dropdown">
            <Link className='profile-link' to="/support">
              Contact
            </Link>
          <li>          
        </ul>
```

**The CSS**

```
.dropdown {
  width: 140px;
  height: 2rem;
  line-height: 2rem;
  cursor: pointer;
  border-bottom: 1px solid white;
}

.profile-link {
  text-decoration: none;
  color: white;
  width: max-content;
  width: 100%;
  height: 100%;
  display: block;
  font-size: 0.9rem
}

.profile-link:hover {
  background-color: #4490E1;
  border-radius: 0.3rem;
}
```

To avoid making the menu unnecessary long, I wanted to place the social icons all in one row. I added a second class to the list-item and changed the `display` property to inline-flex and added `flex: 0.34` to give each 1/3rd of the width.

**The JSX**

```
<li className="dropdown social">
  <a className="profile-link social"
     rel="noopener nofollow noreferrer"
     href="https://dev.to/isarisariver">
       <i className="fab fa-dev" 
          title="DEV Profile">  
       </i>
  </a>
</li>
```

**The CSS**

```
li.dropdown.social {
  display: flex;
  justify-content: space-evenly;
}

.profile-link.social {
  display: inline-flex;
  width: auto;
  font-size: 1.2rem;
  align-items: center;
  flex: 0.34;
  justify-content: center;
  border-radius: 0.3rem;
}
```

## Conclusion

And that's it. I hope it can help you with your next project! If you have any questions, just drop me a message. :smile: