activeClassName in react router is highlighting two NavLinks at the same time - css

I'm learning React Router and following this tutorial
Everything is clear and working as instructed (thank you author) except an issue that highlights the active NavLink.
Take a look at the css file and note the .current class:
nav ul {
list-style: none;
display: flex;
background-color: black;
margin-bottom: 20px;
}
nav ul li {
padding: 20px;
}
nav ul li a {
color: white;
text-decoration: none;
}
.current {
border-bottom: 4px solid white;
}
When I load the app, Home link in the navi is highlighted with a the white bottom border line but it stays highlighted even when I click on the "about" link or the "Contact" link. I followed everything step by step but this one issue I can't figure out.
After reading the react documentaton about the NavLink and many tutorials online, still, don't know how to fix it.
Here is when I click on the about link
Here is when I click on Contact link
This is how the tutorial routes example
<nav>
<ul>
<li><NavLink exact activeClassName="current" to='/'>Home</NavLink></li>
<li><NavLink exact activeClassName="current" to='/about'>About</NavLink></li>
<li><NavLink exact activeClassName="current" to='/contact'>Contact</NavLink></li>
</ul>
</nav>
Notice how the Home link stays with the active white line under it despite the fact that it is not the active link anymore.
Adding activeClassName="current" suppose to highlight the current view with white underline but the home link stays highlighted with the white underline.
So, to all of you out there with years of experience, please help.
Here is My app.js
import React, { Component } from 'react';
import './App.css';
import Main from './components/main';
import Navigation from './components/navigation';
class App extends Component {
render() {
return (
<div>
<h1> React Router </h1>;
<h5> import 'BrowserRouter' from 'react-router-dom' in Appjs</h5>
<hr></hr>
<Navigation />
<Main />
</div>
);
}
}
export default App;
Here is my index.js
import React from 'react';
import ReactDOM from 'react-dom';
//Add browserrouter to use it in your app
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
//this router example is from this site
//https://blog.pusher.com/getting-started-with-react-router-v4/
/*
You can only pass a single child element to a Router,
so it is necessary to create a root component
that renders the rest of your application and
then pass that in as the child of the Router.
*/
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'));
Here is my main.js
import React, { Component } from 'react';
import { NavLink, Switch, Route } from 'react-router-dom';
import Home from './home';
import About from './about'
import Contact from './contact'
class Main extends Component {
render() {
return (
<div>
<p> My main component </p>
<Switch>
<Route exact={true} path='/' component={Home}></Route>
<Route path='/about' component={About}></Route>
<Route path='/contact' component={Contact}></Route>
</Switch>
</div>
);
}
}
export default Main;
And finally here is my navigation.js
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
class Navigation extends Component {
render() {
return (
<div>
<p> My Navigation component </p>
<nav>
<ul>
<li><NavLink to='/'> Home </NavLink> </li>
<li><NavLink to='/about'> About </NavLink> </li>
<li><NavLink to='/contact'> Contact </NavLink> </li>
</ul>
</nav>
</div>
);
}
}
export default Navigation;

The Navlink also needs an exact on it... Change to this:
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
class Navigation extends Component {
render() {
return (
<div>
<p> My Navigation component </p>
<nav>
<ul>
<li><NavLink to='/' activeClassName="current" exact={true}> Home </NavLink> </li>
<li><NavLink to='/about' activeClassName="current"> About </NavLink> </li>
<li><NavLink to='/contact' activeClassName="current"> Contact </NavLink> </li>
</ul>
</nav>
</div>
);
}
}
export default Navigation;

You should add the exact property to your root("") Route, otherwise, it will match every route starting with "", React Router exact
eg:
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
Update:
Also changing the order will have same effect without exact property
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
<Route path="/" component={Home} />
in side a router switch it will go to the first matching route, if we add a route with path / at the beginning it will always render the component in the path, it is better avoid exact fix with order

for v6, use end instead of exact
<NavLink end activeClassName="activeNavLink" to="/">

Remove activeClassName and activeStyle props from <NavLink />
As of v6.0.0-beta.3, the activeClassName and activeStyle props have been removed from NavLinkProps. Instead, you can pass a function to either style or className that will allow you to customize the inline styling or the class string based on the component's active state.
className
<NavLink
to="/"
className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
Home
</NavLink>
style
<NavLink
to="/"
style={({ isActive }) => ({ color: isActive ? 'green' : 'blue' })}
>
Home
</NavLink>
source

exact prop has to be provided to the NavLink component.
It works something like this,
Home
Pictures
When the user clicks on Home, url='/me', it loads home component, when the user clicks on Pictures, url='/me/pictures', if exact is not provided in the NavLink, then both url contains '/me', which makes both of them active.
Its the usecase for exact prop of NavLinks.

You can use exact and strict asper your need in Navlinks.

Related

React sidebar took full width

so I'm trying to create a dashboard page which will show sidebar after user login, But I don't know why my sidebar is taking full width that make my Dashboard component on Routes drop into bottom.
This is the image link of the sidebar https://imgur.com/a/UnSPyaA
My code on App.js :
import Login from './Component/Login';
import Register from './Component/Register.jsx'
import Home from './Component/Home'
import {
BrowserRouter as Router,
Routes,
Route,
} from "react-router-dom";
function App() {
return (
<div className="App">
<Router>
<Routes>
<Route exact path="/" element={<Login/>}/>
<Route path="/register" element={<Register/>}/>
<Route path="/dashboard" element={<Home/>}/>
</Routes>
</Router>
</div>
);
}
export default App;
my code for Home.js:
import React from "react";
import Sidebar from './Sidebar'
import Dashboard from "./Dashboard";
import {Routes, Route} from 'react-router-dom'
import './Home.css'
function Home() {
return (
<>
<Sidebar/>
<Routes>
<Route index element={<Dashboard/>}/>
</Routes>
</>
);
}
export default Home;
The Dashboard Component is just 80 of Lorem text.
This is the code in Sidebar.js and Sidebar.css
import React from 'react'
import './Sidebar.css'
import {Link} from 'react-router-dom'
function Sidebar() {
return (
<div>
<nav className="sidebar">
<Link to="/dashboard">DashBoard</Link>
</nav>
</div>
)
}
export default Sidebar
the Sidebar.css :
.sidebar{
display:flex;
width:200px;
border: 2px solid black;
height:100vh;
background-color:#FFD302;
}
I don't know if this the problem with the CSS or the Router dom. Thanks for the help.
The Home component controls the layout of the HTML/JSX it is rendering. I suggest using a grid layout with 2 columns, one for the sidebar and the other for the descendent routes.
Example:
.home {
display: grid;
grid-template-columns: 1fr 1fr;
}
...
function Home() {
return (
<div className="home"> // <-- parent element
<Sidebar />
<Routes>
<Route index element={<Dashboard />} />
</Routes>
</div>
);
}
try to write your css in sperate file and then attach it by importing i think that is a right way to do work.

Unable to override react-bootstrap using module.css

Im using react bootstrap to make a navbar. Here is the code:
import React from 'react';
import { Link } from "react-router-dom";
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
import styles from './loginHeader.module.css';
const LoginHeader = () => {
return (
<Navbar bg="white" expand="lg">
<Container >
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link >Contact</Nav.Link>
<Nav.Link >Request Demo</Nav.Link>
</Nav>
<Nav >
<NavDropdown className={styles.sample} title="Register" >
<NavDropdown.Item >Patient</NavDropdown.Item>
<NavDropdown.Item ><Link to="/registerOwner" >Owner</Link></NavDropdown.Item>
<NavDropdown.Item >Doctor</NavDropdown.Item>
</NavDropdown>
<Nav.Link><Link to="/" >Login </Link></Nav.Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
)
}
export default LoginHeader;
I want to override the text color of dropdown using loginHeader.module.css. Its given as below:
.sample{
color: #1173bc;
font-weight: bold;
}
but its not changing the color. I have tried using !important key word. Still its not working. Any idea on overriding react-bootstrap properly using css module files?
There is a button element inside the dropdown, in order to change its color you need to pick it with :
.sample .btn{
color:#000000
}

CSS Positioning elements in a header

So I'm trying to create a navigational menu header and it also includes a logo in it, fairly simple but some of the buttons the left side are inline-block with the logo itself and they appear at the bottom of the logo, to the right of it based on ordering, but at the bottom and im not sure how with css to get them to go to the top of the container or if the roof of their container is just lower that I'm thinking?
import React from 'react';
import {Link} from 'react-router-dom';
import { AuthService } from './backend/client/auth';
import { Paper, Button } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles';
const styles = theme => ({
container: {
'height': 128,
},
leftnav: {
'display': 'inline-block',
},
rightnav: {
'float': 'right',
},
button: {
'display': 'inline-block',
}
});
class Header extends React.Component {
render() {
const { classes } = this.props;
return (
<Paper className={classes.container}>
<div className={classes.leftnav}>
<Link to="/" className={classes.button}>
<img src="https://imageserver.eveonline.com/Corporation/98523546_128.png" alt="Hole Puncher's Logo"></img>
</Link>
<Button component={Link} to="/">
Home
</Button>
<Button component={Link} to="/store">
Browse
</Button>
<Button component={Link} to="/contact-us">
Contact Us
</Button>
</div>
<div className={classes.rightnav}>
{AuthService.isAuthed()
? <Button component={Link} to="/account/orders">Account</Button>
: ''}
{AuthService.isAuthed()
? <Button component={Link} to="/login">Login</Button>
: <Button onClick={AuthService.logout} component={Link} to="/login"></Button>}
</div>
</Paper>
)
}
}
export default withStyles(styles)(Header);
https://i.imgur.com/OnTjO4l.png
Multiple ways to solve it using CSS. Simplest way is to use vertical-align: top in your button class. I would however recommend you look into display: flex. It's much easier for vertical alignment.
Working JSFiddle here: http://jsfiddle.net/Lhefbudx/
Hope this helps.

How to change background colors in Reactstrap

I am using react strap to help style an application I'm creating, however I can't figure out how to change the background color of the nav from white to black. I have tried to color ="dark" in the nav tabs tag but that hasn't work. Any help?
import React, { Component } from 'react';
import { Nav, NavItem, Dropdown, DropdownItem, DropdownToggle, DropdownMenu, NavLink } from 'reactstrap';
export default class nav extends React.Component{
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
dropdownOpen: false
};
}
toggle() {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
render() {
return (
<div>
<Nav tabs>
<NavItem>
<NavLink href="/" active>blank.</NavLink>
</NavItem>
<Dropdown nav isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle nav caret>
Dropdown
</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Header</DropdownItem>
<DropdownItem disabled>Action</DropdownItem>
<DropdownItem>Another Action</DropdownItem>
<DropdownItem divider />
<DropdownItem>Another Action</DropdownItem>
</DropdownMenu>
</Dropdown>
<NavItem>
<NavLink href="#">Link</NavLink>
</NavItem>
<NavItem>
<NavLink href="#">Another Link</NavLink>
</NavItem>
<NavItem>
<NavLink href="#">Disabled Link</NavLink>
</NavItem>
</Nav>
</div>
);
}
}
reactstrap doesn't have clear documentation, so I only see here 2 options:
Just use inline styles in the components
<Nav style={{backgroundColor: '#f1f1f1'}}>Something</Nav>
Or use css-modules through
import styles from './Component.module.css'
<Nav className={styles.Component}>Something</Nav>
where you define your ctyles in css
.Component{
background-color: #f1f1f1
}
Note: css-modules sometimes is not enough to override bootstrap styling, but inline styles should help
Utility classes still work with reactstrap. Just use className='bg-dark' on the parent element, and you'll get your dark background.
An approach using styled-components:
const MastHeadJumboTron = styled.div`
&.jumbotron {
background: #000;
}
`;
const MastHead = () => (
<Jumbotron as={MastHeadJumboTron} fluid>
<Container>
<h1>May the force be with you!</h1>
<input placeholder="Filter People" />
</Container>
</Jumbotron>
);
You can create a class with your custom css and mark them !important. Thus over-riding the default styling.
.custom-btn {
background: #000 !important;
}
According to the documentation, for AvField as Input, there are props like inputClass and labelClass that helps you to manage styling for text-box and label respectively.
<AvField
name="member_name"
label="Team Member Name"
inputClass="bg-gradient-primary"
type="text"
placeholder="Name of Team Member"
onChange={this.handleChange}
/>
And for Input Component, you can use className and cssModule for styling purpose.

How to Turn Navbar Collapse into Sidebar in Mobile View using Reactstrap in React.js?

Referring to the image links in the comments below, do you know how to achieve the effects which turn navbar collapse into sidebar properly in mobile view? How to achieve it without affecting and shifting the logo and the button?
//[Home Navbar Desktop View]: https://i.stack.imgur.com/THf6k.jpg
//[Home Navbar Mobile View]: https://i.stack.imgur.com/CiJOc.png
//[Home Navbar/Sidebar Extend Mobile View]: https://i.stack.imgur.com/HhJxQ.png
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from "./components/home/home";
import About from "./components/about/about";
import Portfolio from "./components/portfolio/portfolio";
import Services from "./components/services/services";
import { Collapse, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink, Button } from 'reactstrap';
import './App.css';
import 'tachyons';
class App extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
isOpen: false
};
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return (
<div className='App'>
<Navbar className='sticky-top' color="light" light expand="md">
<NavbarBrand href="/"><b className='logo'>Amecle</b></NavbarBrand>
<NavbarToggler className="order-first" onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink href="/about">About</NavLink>
</NavItem>
<NavItem>
<NavLink href="/services">Services</NavLink>
</NavItem>
<NavItem>
<NavLink href="/portfolio">Portfolio</NavLink>
</NavItem>
</Nav>
</Collapse>
<Button className="still_on_view" outline color="primary">Request a quote</Button>{' '}
</Navbar>
This answer work for me.
At <Navbar className='sticky-top' color="light" light expand="md">
change expand="md" to expand="lg" (this indicate when media at max 1024px (ipad size), will collapse).

Resources