Home > Enterprise >  How can I make an options menu like Google's in my webpage using React?
How can I make an options menu like Google's in my webpage using React?

Time:12-26

I'm trying to make an options menu in my webpage like Gooogle's famous options menu using React: Like this menu

I investigated in a lot of places but I don't know how to do it, I'm using CSS Vanilla for styling.

CodePudding user response:

Here is a codepen code created by SeboFE it's JavaScript code but you can run it in react no problem.

Actually, I do create an empty react project and I have added this pencode to it, and it works fine.

I uploaded the code to GetHub, If you wanna look at it.

HTML Code:

<header >
  <div id="menu-container" class='menu-container' data-is-closed="true">

    <div id="menu-btn" >
      <abbr  title="Google applications">
        <svg viewBox="0 0 24 24">
          <path d="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"></path>
        </svg>
      </abbr>

    </div>

    <div id="menu" >
      <div >

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Account</span>

        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Search</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Maps</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>YouTube</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Play</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>News</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Gmail</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Meet</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Contacts</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Drive</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Calendar</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Translator</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Photos</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Duo</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Chrome</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Shopping</span>
        </a>
      </div>

      <div ></div>

      <div >
        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Docs</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Sheets</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Presentations</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Books</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Blogger</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Hangouts</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Keep</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Jamboard</span>
        </a>

        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Earth</span>
        </a>
        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Collections</span>
        </a>
        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Art and culture</span>
        </a>
        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Google Ads</span>
        </a>
        <a href="#" class='link bg-hover'>
          <i ></i>
          <span>Podcasts</span>
        </a>
      </div>

      <div >

        <button >More from Google</button>
      </div>
    </div>
  </div>
</header>

JS Code:

document.addEventListener("DOMContentLoaded", main);

function main() {
  document.addEventListener("click", handleBgClick);

  const menuContainer = document.querySelector("#menu-container");
  const isMenuClosedAttrName = 'data-is-closed';
  
  const menuBtn = document.querySelector("#menu-btn");
  const menu = document.querySelector("#menu");

  menuBtn.addEventListener("click", toggleMenu);
  menuBtn.addEventListener("click", preventDefault);

  menu.addEventListener("click", preventDefault);

  function preventDefault(e) {
    e.preventDefault();
  }

  function toggleMenu(e) {
    const isMenuClosed = 
     menuContainer.getAttribute(isMenuClosedAttrName);
    if (isMenuClosed === 'true') {
      openMenu();
    } else {
      closeMenu();
    }
  }

  function openMenu() {
    menu.scrollTop = 0;
    menuContainer.setAttribute(isMenuClosedAttrName, 'false');    
  }

  function closeMenu() {
    menuContainer.setAttribute(isMenuClosedAttrName, 'true');    
  }

//   Click on background closes menu.
  function handleBgClick(e) {
    const wentEventNotThroughMenu = !e.path.includes(menu);
    const wentEventNotThroughMenuBtn = !e.path.includes(menuBtn);
    if (wentEventNotThroughMenu && wentEventNotThroughMenuBtn) {
      closeMenu();
    }
  }
}

CSS Code:

body {
  padding-top:3rem;
  box-sizing: border-box;
  color: #202124;
  font-family: "Google Sans", Roboto, RobotoDraft, Helvetica, Arial, sans-serif;
  font-size: 14px;
  letter-spacing: 0.09px;
  line-height: 18px;
  overflow: hidden;
  text-overflow: ellipsis;
}

:root {
  --menu-width: auto;
  --menu-height: 448px;

  --hover-bg-color: #e8f0fe;
  --active-bg-color: #d5e0f2;
}

.clear-df-abbr{
  text-decoration: none;
}

.header-grid {
  display: grid;
  justify-items: center;
}

.menu-container {
  width: 100px;
  position: relative;
}

.menu {
  position: absolute;
  top: 150px;
  left: 50%;
  transform: translateX(-50%);
  width: var(--menu-width);
  height: var(--menu-height);

  background-color: white;
  overflow-y: scroll;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3),
    0 2px 6px 2px rgba(60, 64, 67, 0.15);
}

.menu-btn > svg {
  text-align: center;
  height: 48px;
  width: 48px;
  position: relative;
  display: block;
  color: #5f6368;
}

[data-is-closed="false"] .menu-btn:before {
  content: "";
  background-color: rgba(60,64,67, 0.2);
  border-radius: 50%;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  transform: scale(1.5);
  display: block;
  z-index: -10;
}


[data-is-closed="true"] .menu {
  display: none;
}

.icons-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  gap: 1.5rem;
  padding: 20px 16px 20px 20px;
}

.divider {
  height: 1px;
  background-color: #e8eaed;
}

.link {
  height: 84px;
  width: 84px;

  text-decoration: none;
  color: initial;
  position: relative;
  text-align: center;
  display: inline-block;
  z-index: 10;
}

.link > span {
  white-space: nowrap;
  overflow: hidden;
  width: 76px;
  display: inline-block;
  text-overflow: ellipsis;
}

.bg-hover:hover:before {
  content: "";
  background-color: var(--hover-bg-color);
  border-radius: 8px;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  transform: scale(1.1);
  display: block;
  z-index: -10;
}

[data-is-closed="true"] .circle-hover:hover:before{
  content: "";
  background-color: rgba(60,64,67,0.08);
  border-radius: 50%;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  transform: scale(1.5);
  display: block;
  z-index: -10;
}

.bg-hover:hover:active:before {
  background-color: var(--active-bg-color);
}

.pointer {
  cursor: pointer;
}

.google-icons {
  display: inline-block;
  height: 64px;
  vertical-align: top;
  width: 64px;
  background-image: url("https://ssl.gstatic.com/gb/images/p1_799229b0.png");
  background-size: 64px 2962px;
}

.avatar-icon {
  background-position: 0 -2691px;
}

.search-icon {
  background-position: 0 -690px;
}

.gmail-icon {
  background-position: 0 -1449px;
}

.drive-icon {
  background-position: 0 -1380px;
}

.docs-icon {
  background-position: 0 -2622px;
}

.sheets-icon {
  background-position: 0 -276px;
}

.presentation-icon {
  background-position: 0 -1242px;
}

.calendar-icon {
  background-position: 0 -2829px;
}

.chat.icon {
  background-position: 0 -345px;
}

.meet-icon {
  background-position: 0 -2001px;
}

.sites-icon {
  background-position: 0 -621px;
}

.contacts-icon {
  background-position: 0 -1518px;
}

.discuss-icon {
  background-position: 0 -1104px;
}

.youtube-icon {
  background-position: 0 -1863px;
}

.play-icon {
  background-position: 0 -1035px;
}

.maps-icon {
  background-position: 0 -138px;
}

.news-icon {
  background-position: 0 -414px;
}

.photos-icon {
  background-position: 0 -2760px;
}

.translator-icon {
  background-position: 0 -828px;
}

.duo-icon {
  background-position: 0 -2346px;
}

.chrome-icon {
  background-position: 0 -1725px;
}

.books-icon {
  background-position: 0 -2415px;
}

.art-culture-icon {
  background-position: 0 -1173px;
}

.ads-icon {
  background-position: 0 -552px;
}

.blogger-icon {
  background-position: 0 -966px;
}

.shopping-icon {
  background-position: 0 -2208px;
}

.hangout-icon {
  background-position: 0 -1794px;
}

.keep-icon {
  background-position: 0 -897px;
}

.jamboard-icon {
  background-position: 0 -1932px;
}

.earth-icon {
  background-position: 0 -2277px;
}

.collections-icon {
  background-position: 0 -759px;
}

.podcasts-icon {
  background-position: 0 -1311px;
}

/* ----------------- MORE BUTTON -------------- */

.more-btn-container {
  text-align: center;
  position: relative;
}

.more-btn {
  width: 55%;
  background-color: white;
  border: 1px solid #dadce0;
  border-radius: 4px;
  color: #1a73e8;
  font: 500 14px/16px "Google Sans", Roboto, RobotoDraft, Helvetica, Arial,
    sans-serif;
  margin: 16px 0 20px 0;
  padding: 10px 24px;
}

.more-btn:hover {
  background-color: var(--hover-bg-color);
  border-color: var(--active-bg-color);
}

.more-btn:active {
  outline: 0;
  background-color: var(--active-bg-color);
}

.more-btn:focus {
  outline: 0;
}

.more-btn:focus:active {
  background-color: #ecf3fe;
  border-color: transparent;
  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, 0.3),
    0 2px 6px 2px rgba(60, 64, 67, 0.15);
}

/* ----------------- SCROLLBAR -------------- */

::-webkit-scrollbar {
  width: 16px;
}

::-webkit-scrollbar-thumb {
  background: #dadce0;
  background-clip: padding-box;
  border: 4px solid transparent;
  border-radius: 8px;
  box-shadow: none;
  min-height: 50px;
}

::-webkit-scrollbar-track {
  background: none;
  border: none;
}

CodePudding user response:

Component:

import React from 'react';

export function App(props) {

  const data = [
    {
      title: 'Maps',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Drive',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Docs',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Mail',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Contact',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Maps',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Drive',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Docs',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Mail',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Contact',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Maps',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Drive',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Docs',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Mail',
      imageSrc: '/public/yourimage.png'
    },
    {
      title: 'Contact',
      imageSrc: '/public/yourimage.png'
    },
  ];

  return (
    <div>
     <div className="widget">
        {data.map((data, i) =>
          <div key={i} className="item">
            <img src={data.imageSrc} alt={data.title} />
            <h1>{data.title}</h1>
          </div>
        )}
      </div>
  
    </div>
  );
}

Css:

.widget{
  width: 300px;
  height: 500px;
  background-color: #fff;
  border-radius: 10px;
  position: absolute;
  top: 20px;
  right: 20px;
  display: flex;
  grid-gap: 1rem;
  flex-wrap: wrap;
  overflow: scroll;
}

.item{

  display: flex;
  flex-direction: column;
  align-items: center;
  /* justify-content: start; */
}

You can change the height and the width accordingly.

  • Related