How to detect if React child element is overflowing - javascript

tldr; How do I make my component hide the overflow and make it "toggle" views with a button. ex) user can initially see tab 1,2,3 and 4,5,6 is hidden, a button click will hide the 1,2,3 and show 4,5,6 now (without knowing that the screen will cut after 1,2,3)
I'm trying to make a navbar that can be reused in any screen size. My goal is to allow developers to dynamically add tabs (which is a child element) to the navbar without it overflowing. In the case where the navbar overflows, meaning it makes a new row because it reached its max width, a clickable arrow key goes to the next set of tabs. This is my code so far. How can I achieve this behavior?
Navbar.js
import React, { useState } from 'react';
import Tab from './Tab';
import { StyledTabs } from '../styledComponents/StyledNavbar';
import { NavbarOutline } from '../styledComponents/StyledNavbar';
const Navbar = ({ children }) => {
const [activeTab, setActiveTab] = useState(children[0].props.label);
const onClickTabItem = tab => {
setActiveTab(tab);
}
return (
<>
<NavbarOutline>
<ol>
{children.map(child => {
const { label } = child.props;
return <Tab activeTab={activeTab} key={label} label={label} handleClick={onClickTabItem} />;
})}
</ol>
</NavbarOutline>
<div>
{children.map(child => {
if (child.props.label !== activeTab) return undefined;
return <StyledTabs className="content">{child.props.children}</StyledTabs>
})}
</div>
</>
);
}
export default Navbar;
Tab.js
import React from 'react';
import { StyledTabs } from '../styledComponents/StyledNavbar';
const Tab = props => {
const { activeTab, label, handleClick } = props;
let className = 'not-active';
const onClick = () => {
handleClick(label);
};
if (activeTab === label) {
className = 'active';
}
return (
<StyledTabs className={className} onClick={onClick}>
{label}
</StyledTabs>
);
};
export default Tab;
EDIT: here is my css as well; I used styled components for styling
StyledNavbar.js
import styled from 'styled-components';
export const NavbarOutline = styled.div`
border-bottom: 2px solid #e3e3e3;
padding-left: 0;
display: inline-block;
margin-left: 35px;
margin-right: 35px;
`;
export const StyledTabs = styled.button.attrs(props => ({
className: props.className,
}))`
&.not-active {
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
display: inline-block;
list-style: none;
padding: 16px 31px 16px 31px;
background: none;
border: none;
}
&.active {
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
display: inline-block;
list-style: none;
margin-bottom: -2px;
padding: 16px 31px 16px 31px;
background: none;
border: none;
color: #2b8000;
border-bottom: 2px solid #2b8000;
}
&.content {
display: inline-block;
list-style: none;
background: none;
border: none;
margin-left: 35px;
margin-right: 35px;
`;

This seems like a CSS issue, it would be great if you could've attached the css as well. However, you can solve this using flexbox. Add the following css to the parent container to ensure the tabs create a new row instead of overflowing,
.flex-item {
padding: 5px;
width: 100px;
height: 100px;
margin: 10px;
line-height: 100px;
color: white;
font-weight: bold;
font-size: 2em;
text-align: center;
}
.wrap {
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
}
.wrap li {
background: gold;
}
.flex-container {
padding: 0;
margin: 0;
list-style: none;
border: 1px solid silver;
-ms-box-orient: horizontal;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -moz-flex;
display: -webkit-flex;
display: flex;
}
<ol class="flex-container wrap">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
<li class="flex-item">6</li>
<li class="flex-item">7</li>
<li class="flex-item">8</li>
<li class="flex-item">9</li>
<li class="flex-item">10</li>
</ol>

Related

html select element closes immediately upon a click in ios

My issue is that I have two selects on a page and when I click on anyone one of them, the second one will automatically close when ai touch it, but only when I do it the first click, afterwards it works fine.
Here is my react element
"use client";
import React from "react";
import styles from "./Dropdown.module.scss";
import { BsChevronDown } from "react-icons/bs";
export const Dropdown = ({
name,
value,
onChange,
required = false,
children,
}: {
name: string;
value: string;
onChange: (e: React.ChangeEvent<any>) => void;
required?: boolean;
children: JSX.Element[];
}) => {
return (
<div className={styles.container}>
<select
className={styles.dropdown}
value={value}
name={name}
onChange={onChange}
required={required}
>
{children}
</select>
<div className={styles.caret}>
<BsChevronDown />
</div>
</div>
);
};
Here is my CSS
.container {
position: relative;
display: flex;
align-items: center;
}
.dropdown {
width: 100%;
border-radius: 4px;
height: 45px;
outline: none;
border: 1px solid #e9ecef;
padding: 8px 16px;
background-color: transparent;
cursor: pointer;
font-family: Lato, sans-serif;
font-size: 15px;
letter-spacing: 0.5px;
-moz-appearance: none; /* Firefox */
-webkit-appearance: none; /* Safari and Chrome */
appearance: none;
color: black;
}
.caret {
position: absolute;
right: 16px;
pointer-events: none;
cursor: pointer;
& > svg {
color: #adb5bd;
}
}
I made sure it wasn't caused by CSS.

Navigation bar displayed incorrectly when scrolling and in mobile view

I have a problem with the navigation bar. When it is at the top it should be transparent and the font color in white as soon as the user scrolls a bit the background of the navigation bar should change to white and the font color to black. This also works except for the mobile view.
The icon for the menu is not displayed in black and also if I am at the top (navigation bar is in transparent color) then the mobile menu is also displayed correctly, but if I scroll down a bit and the mobile navigation bar is displayed in white, the mobile navigation bar is displayed in black font which should not be so. How can I solve this problem?
Navigation bar at the top and transparent
Naivgations bar scrolled and in white
MOBILE-VIEW
Mobile navigation bar at the top and transparent
Mobile navigation bar at the top and transparent and when you open the menu
Naivgations bar scrolled and in white
Naivgations bar scrolled and in white and you open the menu
The menu bar should be exactly like the one in the image above and the icon should be in black like picture 4
CODE
Navbar.js
import React, { useState, useEffect } from "react";
import { Button } from "../buttons/Button";
import { Link } from "react-router-dom";
import "./Navbar.css";
function Navbar() {
const [click, setClick] = useState(false);
const [button, setButton] = useState(true);
const [navbar, setNavbar ] = useState(false);
const handleClick = () => setClick(!click);
const closeMobileMenu = () => setClick(false);
const showButton = () => {
if (window.innerWidth <= 960) {
setButton(false);
} else {
setButton(true);
}
};
useEffect(() => {
showButton();
}, []);
window.addEventListener("resize", showButton);
const changeBackground = () => {
if(window.scrollY >= 80) {
setNavbar(true);
}
else {
setNavbar(false);
}
};
window.addEventListener('scroll', changeBackground);
return (
<>
<nav className={navbar ? 'navbar active' : 'navbar'}>
<div className="navbar-container">
<Link to="/" className={navbar ? 'navbar-logo active' : 'navbar-logo'} onClick={closeMobileMenu}>
NAME
<i class="fab fa-typo3" />
</Link>
<div className="menu-icon" onClick={handleClick}>
<i className={click ? "fas fa-times" : "fas fa-bars"} />
</div>
<ul className={click ? "nav-menu active" : "nav-menu"}>
<li className="nav-item">
<Link to="/" className={navbar ? 'nav-links active' : 'nav-links'} onClick={closeMobileMenu}>
Text 1
</Link>
</li>
<li className="nav-item">
<Link
to="/"
className={navbar ? 'nav-links active' : 'nav-links'}
onClick={closeMobileMenu}
>
Text 2
</Link>
</li>
<li className="nav-item">
<Link
to="/"
className={navbar ? 'nav-links active' : 'nav-links'}
onClick={closeMobileMenu}
>
Text 3
</Link>
</li>
<li>
<Link
to="/"
className="nav-links-mobile"
onClick={closeMobileMenu}
>
BUTTON
</Link>
</li>
</ul>
{button && <Button buttonStyle="btn--primary">BUTTON</Button>}
</div>
</nav>
</>
);
}
export default Navbar;
Navbar.css
.navbar {
/*background: #2b41cb;*/
background: transparent;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1.2rem;
position: sticky;
top: 0;
z-index: 999;
margin-bottom: -80px;
}
.navbar-container {
display: flex;
justify-content: center;
align-items: center;
height: 80px;
max-width: 1500px;
}
.navbar-logo {
color: #fff;
justify-self: start;
margin-left: 20px;
cursor: pointer;
text-decoration: none;
font-size: 2rem;
display: flex;
align-items: center;
}
.fa-typo3 {
margin-left: 0.5rem;
font-size: 1.8rem;
}
.nav-menu {
display: grid;
grid-template-columns: repeat(4, auto);
grid-gap: 10px;
list-style: none;
text-align: center;
width: 60vw;
justify-content: end;
margin-right: 2rem;
}
.nav-item {
height: 80px;
}
.nav-links {
color: #fff;
display: flex;
align-items: center;
text-decoration: none;
padding: 0.5rem 1rem;
height: 100%;
}
.nav-links:hover {
border-bottom: 4px solid #fff;
transition: all 0.2s ease-out;
}
.fa-bars {
color: #fff;
}
.nav-links-mobile {
display: none;
}
.menu-icon {
display: none;
}
#media screen and (max-width: 960px) {
.NavbarItems {
position: relative;
}
.nav-menu {
display: flex;
flex-direction: column;
width: 100%;
height: 90vh;
position: absolute;
top: 80px;
left: -100%;
opacity: 1;
transition: all 0.5s ease;
}
.nav-menu.active {
background: #242222;
left: 0;
opacity: 1;
transition: all 0.5s ease;
z-index: 1;
}
.nav-links {
text-align: center;
padding: 2rem;
width: 100%;
display: table;
}
.nav-links:hover {
background-color: #fff;
color: #242424;
border-radius: 0;
}
.navbar-logo {
position: absolute;
top: 0;
left: 0;
transform: translate(25%, 50%);
}
.menu-icon {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
.fa-times {
color: #fff;
font-size: 2rem;
}
.nav-links-mobile {
display: block;
text-align: center;
margin: 2rem auto;
border-radius: 4px;
width: 80%;
text-decoration: none;
font-size: 1.5rem;
background-color: goldenrod;
color: #fff;
padding: 14px 20px;
border: 1px solid goldenrod;
transition: all 0.3s ease-out;
border-radius: 25px;
}
.nav-links-mobile:hover {
background: goldenrod;
transition: 250ms;
}
}
/* NAVBAR ACTIVE */
.navbar.active {
/*background: linear-gradient(90deg, rgb(66, 2, 194) 0%, rgb(0, 78, 194) 100%)*/
background: #fff;
border-bottom: 2px solid #e8e8e8;
}
.navbar-logo.active {
color: #000;
}
.nav-links.active {
color: #000;
}
.nav-links.active:hover {
border-bottom: 4px solid #000;
transition: all 0.2s ease-out;
}
Is not necessary, but for it to run
HeroSection.js
import React from 'react';
import '../../App.css';
import { Button } from '../buttons/Button';
import './HeroSection.css';
function HeroSection() {
return (
<div className='hero-container'>
<h1>Heading One</h1>
<p>Some Text!</p>
<div className='hero-btns'>
<Button
className='btns'
buttonStyle='btn--outline'
buttonSize='btn--large'
>
BUTTON 1
</Button>
<Button
className='btns'
buttonStyle='btn--primary'
buttonSize='btn--large'
>
BUTTON 2 <i className='far fa-arrow-alt-circle-right' />
</Button>
</div>
</div>
);
}
export default HeroSection;
HeroSection.css
video {
object-fit: cover;
width: 100%;
height: 100%;
position: fixed;
z-index: -1;
}
.hero-container {
background: rgba(102, 232, 255, 0.849);
height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/*box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, 0.2);*/
object-fit: contain;
}
.hero-container > h1 {
color: #fff;
font-size: 100px;
margin-top: -100px;
}
.hero-container > p {
margin-top: 8px;
color: #fff;
font-size: 32px;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande',
'Lucida Sans', Arial, sans-serif;
}
.hero-btns {
margin-top: 32px;
}
.hero-btns .btn {
margin: 6px;
}
.fa-play-circle {
margin-left: 4px;
}
#media screen and (max-width: 960px) {
.hero-container > h1 {
font-size: 70px;
margin-top: -150px;
}
}
#media screen and (max-width: 768px) {
.hero-container > h1 {
font-size: 50px;
margin-top: -100px;
}
.hero-container > p {
font-size: 30px;
}
.btn-mobile {
display: block;
text-decoration: none;
}
.btn {
width: 100%;
}
}
Home.js
import React from 'react';
import '../../App.css';
import Cards from '../cards/Cards';
import Footer from '../footer/Footer';
import HeroSection from '../Hero/HeroSection';
import Box from '../box/Box';
function Home() {
return (
<>
<HeroSection></HeroSection>
</>
)
}
export default Home;
App.js
import React from 'react'
import Navbar from './components/navbar/Navbar'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Home from './components/pages/Home';
import './App.css'
function App() {
return (
<>
<Router>
<Navbar/>
<Switch>
<Route path='/' exact component={Home} />
</Switch>
</Router>
</>
);
}
export default App;
may you need different class for you different Navigation button in different situation added it dynamically:)
window.addEventListener("resize", showButton);
const changeBackground = () => {
let scrollClass = '';
if(window.scrollY >= 80) {
setNavbar(true);
scrollClass = 'black';
}
else {
setNavbar(false);
scrollClass = '';
}
this.setState({ scrollClass });
<div className="menu-icon" onClick={handleClick}>
<i className={`click ? "fas fa-times" : "fas fa-bars" ${this.state.scrollClass }`} />
</div>

How can i use onClick event in styled component

I have a problem with styled. I will write my problem with images. I have a image button and if i click on image button, the MenuItemContainer must be visibility.
const MenuItemContainer = styled.div`
visibility: hidden;
display: inline-block;
box-sizing: border-box;
width: 200px;
padding-left: 16px;
padding-right: 16px;
border: 1px solid ${({ theme }) => theme.palette.lightBlueGrey};
border-radius: 5px;
box-shadow: 0 12px 24px 0px ${({ theme }) => theme.palette.dark15};
`;
const ProfileNameWrapper = styled.div`
display: flex;
width: 36px;
height: 36px;
border-radius: 50%;
margin-right: 25px;
background-color: ${({ theme }) => theme.palette.darkGreyBlue};
cursor: pointer;
justify-content: center;
align-items: center;
&:hover ${TooltipText} {
visibility: visible;
}
&:????? ${MenuItemContainer} {
visibility: visible;
}
`;
can i use onClick here?
&:????? ${MenuItemContainer} {
visibility: visible;
}
Even though, I find it wrong to attach click events on divs, you can utilize the aria attributes to hack your way around your problem.
const ProfileNameWrapper = styled.div`
...
&:[aria-expanded='true'] ${MenuItemContainer} {
visibility: visible;
}
`
const Component: React.FC<Props> = (props) => {
const [expanded, setExpanded] = React.useState(false)
return (
<ProfileNameWrapper onClick={() => setExpanded(!expanded)} aria-expanded={expanded} />
)
}

How to check if element is displayed or hidden from overflow?

I have a navbar component as shown below with a bunch of tabs that are displayed dynamically depending on how many components the developer passes in to Navbar.js. If the amount of tabs overflow, it is automatically hidden and cut off from the fixed width of the parent div component. Now I want to add an arrowLeft and arrowRight component that lets the user click to scroll to show the hidden tabs. How would I go about this? I'm really hoping for a solution without the need of jquery.
Navbar.js
import React, { useState } from 'react';
import Tab from './Tab';
import Filter from './Filter';
import { StyledTabs, NavbarOutline, arrowLeft, arrowRight } from '../styledComponents/StyledNavbar';
const Navbar = ({ value, tabFilter, contentFilter }) => {
const [activeTab, setActiveTab] = useState(value[0].title);
const onClickTabItem = tab => {
setActiveTab(tab);
}
return (
<React.Fragment>
<NavbarOutline>
<ol>
<arrowLeft />
</ol>
<ol>
{value.map(child => {
const { title } = child;
return <Tab activeTab={activeTab} key={title} title={title} handleClick={onClickTabItem} />;
})}
</ol>
<ol>
{tabFilter && !contentFilter && <Filter key="tabFilter" tab />}
{contentFilter && !tabFilter && <Filter key="contentFilter" content />}
<arrowRight />
</ol>
</NavbarOutline>
<div>
{value.map(child => {
if (child.title !== activeTab) return undefined;
return <StyledTabs className="content">{child.title}</StyledTabs>
})}
</div>
</React.Fragment>
);
}
export default Navbar;
StyledNavbar.js (styled-components)
import styled from 'styled-components';
export const NavbarOutline = styled.div`
margin-left: 35px;
margin-right: 35px;
overflow-x: auto;
white-space: nowrap;
top: 0px;
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
&::-webkit-scrollbar {
display: none; /* Safari and Chrome */
}
`;
export const StyledTabs = styled.button.attrs(props => ({
className: props.className,
}))`
&.not-active {
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
list-style: none;
padding: 16px 31px 16px 31px;
background: none;
border: none;
border-bottom: 2px solid #e3e3e3;
z-index: -1;
}
&.active {
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
list-style: none;
margin-bottom: -2px;
padding: 16px 31px 16px 31px;
background: none;
border: none;
color: #2b8000;
border-bottom: 3px solid #2b8000;
z-index: -1;
}
&.content {
list-style: none;
background: none;
border: none;
margin-left: 35px;
margin-right: 35px;
}
&.filter {
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
list-style: none;
position: relative;
padding: 16px 31px 16px 31px;
border: none;
border-bottom: 2px solid #e3e3e3;
display: block;
margin-top: -54px;
background: white;
right: 0px;
}
`;
What you are looking for is called an intersectionObserver. There's a native DOM API, but I recommend going with the react-intersection-observer package. It's well maintained and documented.
You'll want to use the useInView hook to create refs for every DOM node you want to keep track of, and use the parent component as root for them. Then you show the arrows conditionally depending on which refs' inView === true.
To scroll you can use the native scrollIntoView() API, or use a react package for that as well.

Drop down menu using styled-components: How to properly use class selectors?

Using styled components, I want to build a React component that will mimic the following code from W3 Schools:
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
}
li {
float: left;
}
li a, .dropbtn {
display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
li a:hover, .dropdown:hover .dropbtn {
background-color: red;
}
li.dropdown {
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-content a:hover {background-color: #f1f1f1;}
.dropdown:hover .dropdown-content {
display: block;
}
<body>
<ul>
<li>Home</li>
<li>News</li>
<li class="dropdown">
Dropdown
<div class="dropdown-content">
Link 1
Link 2
Link 3
</div>
</li>
</ul>
<h3>Dropdown Menu inside a Navigation Bar</h3>
<p>Hover over the "Dropdown" link to see the dropdown menu.</p>
</body>
</html>
Here is my React Component:
import React, { Component } from "react";
import PropTypes from "prop-types";
import styled, { ThemeProvider } from "styled-components";
const StyledUl = styled.ul`
list-style-type: none;
margin: 0;
overflow: hidden;
background-color: #333;
padding: 0px;
background-color: lightblue;
color: black;
font-weight: bold;
`;
const StyledLi = styled.li`
float: left;
height: 100%;
padding: 10px;
&:hover {
background-color: red;
}
`;
const DropDownContent = styled.div`
display: none;
position: absolute;
min-width: 160px;
z-index: 1;
`;
const DropDownLi = styled(StyledLi)`
display: inline-block;
&:hover ${DropDownContent} {
display: block;
}
`;
const StyledA = styled.a`
display: inline-block;
text-align: center;
text-decoration: none;
`;
const SubA = styled(StyledA)`
text-decoration: none;
display: block;
text-align: left;
background-color: lightblue;
padding: 10px;
`;
class Menu extends Component {
handleClick = action => {
if (!action) return;
if (this.props.onClick) this.props.onClick(action);
};
render = () => {
return (
<StyledUl>
<StyledLi>
<StyledA onClick={() => this.handleClick("Home")}>
Home
</StyledA>
</StyledLi>
<StyledLi>
<StyledA onClick={() => this.handleClick("News")}>
Home
</StyledA>
</StyledLi>
<DropDownLi>
<StyledA onClick={() => this.handleClick("DropDown")}>
DropDown
</StyledA>
<DropDownContent>
{" "}
<SubA onClick={() => this.handleClick("Link1")}>
Link 1
</SubA>
<SubA onClick={() => this.handleClick("Link2")}>
Link 2
</SubA>
<SubA onClick={() => this.handleClick("Link3")}>
Link 3
</SubA>
</DropDownContent>
</DropDownLi>
</StyledUl>
);
};
}
export default Menu;
The result is not the same, basically because I'm not sure how to work with selectors inside styled-component.
How can I fix my ReactJs component Menu code to behave exactly like the W3 example?
You made some minor mistakes in translating the code, but the syntax and concepts were all correct. Your use of selectors is correct:
/* Hovering over current component */
&:hover {
background-color: red;
}
/* Selecting another styled component */
/* calls DropDownContent.toString(), which returns */
/* the class name of the styled component: .sc-bxivhb */
&:hover ${DropDownContent} {
display: block;
}
Here is a corrected version:
import React, { Component } from "react";
import styled from "styled-components";
const StyledUl = styled.ul`
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
`;
const StyledLi = styled.li`
float: left;
`;
const Dropbtn = styled.div`
display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
`;
const DropDownContent = styled.div`
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
`;
const DropDownLi = styled(StyledLi)`
display: inline-block;
&:hover {
background-color: red;
}
&:hover ${DropDownContent} {
display: block;
}
`;
const StyledA = styled.a`
display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
&:hover {
background-color: red;
}
`;
const SubA = styled.a`
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
&:hover {
background-color: #f1f1f1;
}
`;
class Menu extends Component {
handleClick = action => {
if (!action) return;
if (this.props.onClick) this.props.onClick(action);
};
render = () => {
return (
<StyledUl>
<StyledLi>
<StyledA onClick={() => this.handleClick("Home")}>Home</StyledA>
</StyledLi>
<StyledLi>
<StyledA onClick={() => this.handleClick("News")}>Home</StyledA>
</StyledLi>
<DropDownLi>
<Dropbtn onClick={() => this.handleClick("DropDown")}>
DropDown
</Dropbtn>
<DropDownContent>
{" "}
<SubA onClick={() => this.handleClick("Link1")}>Link 1</SubA>
<SubA onClick={() => this.handleClick("Link2")}>Link 2</SubA>
<SubA onClick={() => this.handleClick("Link3")}>Link 3</SubA>
</DropDownContent>
</DropDownLi>
</StyledUl>
);
};
}
export default Menu;
You need to do it scss-like syntax. In order to use pseudo selectors like hover you need to do Nesting and use The ampersand (&) which will refer back to the main selector. Also you could use the regular class selector if you like.
Your code example:
export const Menu = styled.ul `
/* main UL component called: "Menu" */
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #333;
/* main LI */
& > li {
float: left;
& > a {
display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
&:hover {
background-color: red;
}
}
}
/* dropdown LI */
& > .dropdown {
display: inline-block;
& > .dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
& > a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
&:hover {
background-color: #f1f1f1;
}
}
}
&:hover .dropdown-content {
display: block
}
}
`
And for the JSX part, Just call Menu component
<Menu>
<li>Home</li>
<li>News</li>
<li className="dropdown">
Dropdown
<div className="dropdown-content">
Link 1
Link 2
Link 3
</div>
</li>
</Menu>
That way, I've only created one component called Menu and all JSX elements are Nested just like normal HTML.
See full example at codesandbox:

Categories