I'm trying to make an options menu in my webpage like Gooogle's famous options menu using React:
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.