How to style active navigator item in the navbar? - javascript

I am working with Reactjs using html, css, and javascript.
I want to style active navigator item in the navbar with white border. That is mean the border will stay in the item while the page of this item is open.
import React, { useState } from "react";
import { Link } from "react-router-dom";
import "./Navbar.css";
import { navItems } from "./NavItems";
import Dropdown from "./Dropdown";
function Navbar() {
const [dropdown, setDropdown] = useState(false);
return (
<>
<nav className="navbar">
<ul className="nav-items">
{navItems.map((item) => {
if (item.id === "C3") {
return (
<li
key={item.id}
className={item.cName}
id={window.location.pathname === item.path? "C10":""}
onMouseClick={() => setDropdown(true)}
onMouseEnter={() => setDropdown(true)}
onMouseLeave={() => setDropdown(false)}
>
<Link to={item.title}>{item.title}</Link>
{dropdown && <Dropdown />}
</li>
);
}
return (
<li key={item.id}
className={item.cName}
id={window.location.pathname === item.path? "C10":""}
>
<Link to={item.path}>{item.title}</Link>
</li>
);
})}
</ul>
</nav>
</>
);
}
export default Navbar;
This is the CSS file
.nav-item a:hover {
border: solid 2px white;
}
#C10{
border: solid 2px white;
}
I try to use this method in CSS file.
.nav-item a:active {
border: solid 2px white;
}
and I use this method in CSS file and JS file also but it does not work!
id={window.location.pathname === item.path? "C10":""}
#C10{
border: solid 2px white;
}

If you want to style an active <Link/> you have to use a <Navlink/> instead.
Check the doc: https://reactrouter.com/en/main/components/nav-link

As William said you are better off using the actual <NavLink/> elements then programming plain html in React. However you can also create a function that adds the active class to the li item when it's selected.
See this example:
const links = ['https://google.com', 'https://google.be', 'https://google.nl'];
const [active, setActive] = useState(null);
<ul>
{links.map((link) => (
<li className="nav-item">
<a
href={`#${link}`}
className={`nav-link ${active == link && 'm-active'}`}
onClick={() => setActive(link)}
>{link}</a>
</li>
))}
</ul>

Related

NavLink Active property does not work with nested pages

I am using Reactjs in my project. NavLink active property does not work with nested pages inside the same tab?? It works just in the main tab anything inside the main tab does not work with. I want the white border appear in the main tab while open any pages inside it.
import { NavLink } from "react-router-dom";
function Navbar() {
let activeStyle = {
border: "solid 3px #FFF",
};
return (
<>
<nav className="navbar">
<ul className="nav-items">
{navItems.map((item) => {
if (item.id === "3") {
return (
<li
key={item.id}
className={item.cName}
onMouseClick={() => setDropdown(true)}
onMouseEnter={() => setDropdown(true)}
onMouseLeave={() => setDropdown(false)}
>
<NavLink to={item.title}
style={({ isActive }) =>
isActive ? activeStyle: undefined
}
>{item.title}</NavLink>
{dropdown && <Dropdown />}
</li>
);
}
return (
<li key={item.id}
className={item.cName}>
<NavLink to={item.path}
style={({ isActive }) =>
isActive ? activeStyle: undefined
}>{item.title}</NavLink>
</li>
);
})}
</ul>
</nav>
</>
);
}
export default Navbar;

I want my button to Change it value to the currency I select

What I want is when I select "AUD" from the dropdown menu my button's("dropbtn") innerHtml changes to "AUD" similarly other way around. I want my button to change its text to the text of the I select from my dropdown menu
Here is the code:
App.js:
import './App.css'
import React, { useState, useEffect, useRef } from "react";
export default function App() {
const [listopen, setListopen] = useState(false)
const Dropdown = () => {
if (listopen) {
setListopen(false)
} else {
setListopen(true)
}
}
return (
<main>
<nav>
<ul>
<div class="dropdown">
<li><button class="dropbtn" onClick={() => Dropdown()} >USD
</button></li>
<div class="dropdown-content" id="myDropdown" style={{ display: listopen === false ? 'none' : 'block' }}>
AUD($)
USD($)
PKR($)
</div>
</div>
</ul>
</nav>
</main>
)
}
App.css:
.dropdown-content {
display: none;
position: absolute;
background-color: #1a2456;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 100;
width: 9.5vw;
}
.dropdown-content a {
float: none;
color: #fead94;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
z-index: 100;
}
You could use a state for the text on the button and have a click event on the dropdrown
export default function App() {
const [listopen, setListopen] = useState(false)
const [btnText, setBtnText] = useState("Default Text");
const Dropdown = () => {
setListopen(!listopen) //Same functionality as yours but less code
}
const handleOptionClick = (txt)=> {
setBtnText(txt);
}
return (
<main>
<nav>
<ul>
<div class="dropdown">
<li><button class="dropbtn" onClick={() => Dropdown()}> {btnText}
</button></li>
<div class="dropdown-content" id="myDropdown" style={{ display: listopen === false ? 'none' : 'block' }}>
<a href="/" onClick={()=> handleOptionClick("AUD")}>AUD($)</a>
<a href="/" onClick={()=> handleOptionClick("USD")}>USD($)</a>
<a href="/"onClick={()=> handleOptionClick("PKR")}>PKR($)</a>
</div>
</div>
</ul>
</nav>
</main>
)
}
Also you can modify DropDown function for less code like I did
using your code
import React, { useState } from "react";
export default function App() {
const [listopen, setListopen] = useState(false);
const Dropdown = () => {
if (listopen) {
setListopen(false);
} else {
setListopen(true);
}
};
const [value, setValue] = useState("USD");
const handleChangeValue = (e) => {
e.preventDefault();
setValue(e.target.id);
};
return (
<main>
<nav>
<ul>
<div class="dropdown">
<li>
<button className="dropbtn" onClick={() => Dropdown()}>
{value}
</button>
</li>
<div
class="dropdown-content"
id="myDropdown"
style={{ display: listopen === false ? "none" : "block" }}
>
<a href="/" id="AUD" onClick={handleChangeValue}>
AUD($)
</a>
<a href="/" id="USD" onClick={handleChangeValue}>
USD($)
</a>
<a href="/" id="PKR" onClick={handleChangeValue}>
PKR($)
</a>
</div>
</div>
</ul>
</nav>
</main>
);
}
using select tag
import React, { useState } from "react";
export default function App() {
const [selectedValue, setSelectedValue] = useState("AUD");
const handleSelectChange = (e) => {
setSelectedValue(e.target.value);
};
return (
<>
<p>{selectedValue}</p>
<select id="select" onChange={handleSelectChange}>
<option value="">--Please choose an option--</option>
<option value="AUD">AUD</option>
<option value="USD">USD</option>
<option value="PKR">PKR</option>
</select>
</>
);
}
hope it was helpful to you!

Style hover on mapped array using Reactjs

I am trying to style the ListItem on hover, but the problem is that the list is being mapped over to create multiple list items. When I change the hover style it changes the style for all list items when being hovered. How do I target just one element? Below is the code.
I am trying to style the prop.icon and ListItemText when they are hovered.
Sidebar.js
var links = (
<List className={classes.list}>
{routes.map((prop, key) => {
if (prop.path === "/login") {
return;
}
return (
<NavLink
to={prop.layout + prop.path}
className={classes.item}
activeClassName="active"
key={key}
>
<ListItem button className={classes.itemLink} onMouseEnter={MouseEnter} onMouseLeave={MouseLeave}>
<prop.icon
className={classNames(classes.itemIcon)}
/>
<ListItemText
primary={prop.name}
className={classNames(classes.itemText)}
disableTypography={true}
/>
</ListItem>
</NavLink>
);
})}
</List>
);
MouseEnter & MouseLeave
const MouseEnter = (e) => {
setHovered(true);
}
const MouseLeave = (e) => {
setHovered(false);
}
With CSS it would be as simple as that:
.list-item:hover{
background-color: purple;
color: white;
}
/* just for decoration, you don't need the code below*/
ul{
list-style-type: none;
}
li{
padding: 1rem;
cursor: pointer;
border: solid 1px black;
margin: 0.5rem;
}
<script src="https://kit.fontawesome.com/a076d05399.js"></script>
<ul >
<li class="list-item" >
<span >♠ </span>spades
</li>
<li class="list-item">
<span >♣ </span>clubs
</li>
<li class="list-item">
<span >♦ </span>dimonds
</li>
</ul>
or with your code:
//links.css
.list-item:hover{
background-color:red;
}
//links.js
import "./links.css"
var links = (
<List className={classes.list}>
{routes.map((prop, key) => {
if (prop.path === "/login") {
return;
}
return (
<NavLink
to={prop.layout + prop.path}
className={classes.item}
activeClassName="active"
key={key}
>
<ListItem button className={classes.itemLink + " list-item"} onMouseEnter={MouseEnter} onMouseLeave={MouseLeave}>
<prop.icon
className={classNames(classes.itemIcon)}
/>
<ListItemText
primary={prop.name}
className={classNames(classes.itemText)}
disableTypography={true}
/>
</ListItem>
</NavLink>
);
})}
</List>
);
Using the active index in the array worked for me besides using boolean values.
sidebar.js
const [hovered, setHovered] = useState(-1);
const MouseEnter = (index) => {
setHovered(index);
}
const MouseLeave = () => {
setHovered(-1);
}
var links = (
<List className={classes.list}>
{routes.map((prop, index, key ) => {
if (prop.path === "/login") {
return;
}
return (
<NavLink
to={prop.layout + prop.path}
className={classes.item}
activeClassName="active"
key={key}
>
<ListItem button className={hovered === index ? 'hoverLinear' : classes.itemContainer} onMouseEnter={() => MouseEnter(index)} onMouseLeave={MouseLeave}>
<prop.icon
className={classNames(classes.itemIcon)}
style={hovered === index ? {color: 'white'} : {color: "#8B2CF5"}}
/>
<ListItemText
primary={prop.name}
className={classNames(classes.itemText, ' mx-10')}
style={hovered === index ? {color: 'white'} : {color: "#3A448E"}}
disableTypography={true}
/>
</ListItem>
</NavLink>
);
})}
</List>
);

React way to open a NavBar onClick on a button

I trying to find a way to open the navbar of ReactJS app when i'm clicking on my "MENU" button.
At the beginning my nav component have a width of 0px (with overflow : hidden). When i'm clicking on the button my nav should have a width of 400px. I'm a beginner with React.
I have two React Components :
Topbar
export default function Topbar() {
return (
<div className="topbar__container">
<div className='topbar__menuButton'>
<Link className="topbar__link">MENU</Link>
</div>
<div className="topbar__title">
<Link to="/" className="topbar__link">EDGAR</Link>
</div>
</div>
)
}
Nav
const Nav = () => {
return (
<div className="navbar__container">
<Query query={CATEGORIES_QUERY} id={null}>
{({ data: { categories } }) => {
return (
<nav className="nav">
<ul>
{categories.map((category, i) => {
return (
<li key={category.id}>
<Link to={`/category/${category.id}`} className="nav__link">
{category.name}
</Link>
</li>
)
})}
</ul>
</nav>
)
}}
</Query>
</div>
)
}
export default Nav
To achieve something like that you have to set this logic in the common parent of both component (here App for the example).
App will manage a state to determine if the Nav is open or not. The state is called isMenuOpen and can be changed using the setIsMenuOpen() function. We will give to the children Nav the state isMenuOpen and to the children TopBar a callback from the function setIsMenuOpen():
App.jsx
import React from "react";
import TopBar from "./TopBar";
import Nav from "./Nav";
export default function App() {
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
return (
<div className="App">
<TopBar setMenuStatus={setIsMenuOpen} />
<Nav isOpen={isMenuOpen} />
</div>
);
}
Then the TopBar have to set the value of isMenuOpen to true using the function setIsMenuOpen() from the props.
TopBar.jsx
import React from "react";
export default function Topbar({ setMenuStatus }) {
return (
<div className="topbar__container">
<div className="topbar__menuButton">
<button
type="button"
onClick={() => {
setMenuStatus(true);
}}
>
Menu
</button>
</div>
</div>
);
}
Then the component Nav will set a specific class (here .open) if isOpen coming from props is true.
Nav.jsx
import React from "react";
import "./styles.css";
export default function Nav({ isOpen }) {
return (
<div id="nav" className={isOpen ? "open" : ""}>
Menu
</div>
);
}
styles.css
#nav {
display: none;
}
#nav.open {
height: 400px;
display: inline-block;
}
You can try this example in this codesandbox.
import React, {useState} from "react";
import "./styles.css";
export default function App() {
const [toggle, setToggle]= React.useState(false)
const [width, setWidth]= React.useState('')
const showMenu = () => {
setToggle(!toggle)
if(toggle === true) {
setWidth('50px')
}else {
setWidth('500px')
}
}
return (
<div className="App">
<button onClick={showMenu}>Menu</button>
<div style={{width, border:'1px solid red'}}>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</div>
</div>
);
}
reproducing link: https://codesandbox.io/s/billowing-flower-rxdk3?file=/src/App.js:0-592

React.js Popup modal for shopping cart

I am currently working on a shopping cart and I am trying to figure out how to have the modal appear once I click on the shopping cart icon. I have looked at the documentation for the semantic-ui for modals but it is vague as to how to get the modal to appear when clicking on something. I am using the semantic-ui class="ui modal" for the modal.
I was thinking of putting an onClick on the icon but was still confused as to how to go from there. Currently, I have the icon in another component and the shopping cart in another separate component. I want the items to appear inside of the pop-up modal which should be the shopping cart.
import React from 'react'
import { Icon } from 'semantic-ui-react';
const ShoppingCartIcon = () => {
return(
<Icon.Group size='big' className="shopping_cart_icon">
<Icon link name='shopping cart'/>
<Icon corner='top right'/>
</Icon.Group>
)
}
export default ShoppingCartIcon;
import React from 'react'
import Shirt from './Shirt';
class ShoppingCart extends React.Component {
render() {
const listShirts = this.props.shirts.map(shirt => {
return <Shirt key={shirt.id} {...shirt}/>
})
return(
<div className="ui modal">
<div className="content">
{listShirts}
</div>
</div>
)
}
}
export default ShoppingCart;
Currently, I do not have the functionality for adding items to the cart working yet. I just want to focus on getting the modal to show up once I click on the shopping cart icon
as far as I see, you are not using neither redux nor context api. you are passing props with props drilling.
so this is how you should organize your code step by step.
we render cartIcon component in the header.js. here is a classic header
Header.js
import CartDropdown from "../cart-dropdown/cart-dropdown.component";
class Header extends React.Component {
constructor(props) {
super(props);
state = { hidden: true, cartItems:[]};
}
toggleHidden() {
this.setState(() => ({ hidden: !this.state.hidden }));
}
render() {
return (
<div className="header">
<Link className="logo-container" to="/">
<Logo className="logo" />
</Link>
<div className="options">
<Link className="option" to="/shop">
SHOP
</Link>
<Link to="/contact" className="option">
CONTACT
</Link>
{/* <Link></Link> */}
<CartIcon />
</div>
{hidden ? null : (
<CartDropdown
toggle={this.toggleHidden}
cartItems={this.state.cartItems}
></CartDropdown>
)}
</div>
);
}
}
you said you have not set the addItem functionality yet. as you add items to the cartItems array you will display them in the cart.
now we need to set up the cartDropdown component.
const CartDropdown = ({ cartItems, toggleHidden }) => (
<div className="cart-dropdown">
<div className="cart-items">
{cartItems.length ? (
cartItems.map(item => <CartItem key={item.id} item={item} />)
) : (
<span className="empty-message"> Your cart is empty </span>
)}
</div>
<CustomButton
onClick={() => {
toggleHidden();
}}
>
GO TO CHECKOUT
</CustomButton>
</div>
);
here we need to add css for cartDropdown. I do not how you are dealing with your css. prop-types or scss but here is the css code so you can apply to your project.
css for cartDropdown component
.cart-dropdown {
position: absolute;
width: 240px;
height: 340px;
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid black;
background-color: white;
top: 80px;
right: 0;
z-index: 5;
.cart-items {
height: 240px;
display: flex;
flex-direction: column;
overflow: scroll;
}
.empty-message {
font-size: 18px;
margin: 50px auto;
}
button {
margin-top: auto;
}
}

Categories

Resources