In react-router v3 we had activeStyle and activeClassName to style active Link
we could do something like this
<div id="tags-container">
{tags.map(t =>
<Link
className="tags"
activeStyle={{ color: 'red' }}
to={t.path}
>
{t.title}
</Link>
)}
</div>
I wanna know how can I do same thing in v4?
Use NavLink instead Link. Its not documented, but its work as you expect.
https://github.com/ReactTraining/react-router/issues/4318
UPDATE 17.05.2017:
https://reacttraining.com/react-router/web/api/NavLink
You can do it with NavLink in react-router v4
<div id="tags-container">
{tags.map(t =>
<NavLink
className="tags"
activeStyle={{ color: 'red' }}
to={t.path}
>
{t.title}
</NavLink>
)}
</div>
If you are encountering an issue where your Nav menu works except it's not updating properly when you click links and the route changes, but it works fine if you press F5, you can do this:
This is probably occurring because you are using Redux which has a shouldComponentUpdate Lifecycle method on its connect function. You probably have your Nav component wrapped in connect. This is all good. shouldComponentUpdate is what is ruining your life.
To fix, just bring the router into your mapStateToProps function:
// This lets shouldComponentUpdate know that the route changed,
// which allows the Nav to re-render properly when the route changes, woot!
const mapStateToProps = (state) => {
return {
router: state.router,
}
}
// or, if you prefer pro style destructure shorthand:
const mapStateToProps = ({ router }) => ({ router })
If you aren't quite sure where state.router comes from, it comes from the file you combine your reducers in, and you will see something like this:
import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'
import authReducer from './components/auth/auth_reducer'
export default combineReducers({
router: routerReducer,
auth: authReducer,
})
Here is some HTML and CSS for a pretty baller Nav Link:
HTML
<ul id="Nav_menu">
<li>
<NavLink
to="/home"
className="Nav_link"
activeClassName="activeRoute"
activeStyle={{ color: 'teal' }}
>
HOME
</NavLink>
</li>
<li>
<NavLink
to="/products"
className="Nav_link"
activeClassName="activeRoute"
activeStyle={{ color: 'teal' }}
>
PRODUCTS
</NavLink>
</li>
</ul>
NOTE: If you are linking to "/", put exact prop on NavLink.
CSS
#Nav_menu {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
list-style-type: none;
margin: 0;
padding: 0;
}
.Nav_link:link {
color: #fff;
font-size: 1.6rem;
line-height: 1.6rem;
text-decoration: none;
}
.Nav_link:visited {
color: #fff;
}
.Nav_link:hover {
color: yellow;
}
.Nav_link:active {
color: teal;
}
.activeRoute {
background-color: yellow;
border-bottom: 0.4rem solid teal;
cursor: not-allowed;
}
Notice activeStyle in the HTML markup. This was the only way I could change the color of the text on the active route/link. It didn't work when I put color: teal; in the activeRoute CSS Class. Open this in another tab: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/NavLink.md
If you don't know why I used rem instead of px. This is a great opportunity for you to research web accessibility and base font-size: 10px;.
Stay fit and have fun.
React Router v6:
Source: Active NavLink Classes with React Router
I know this was a question for v4 but since v6 is released we can accomplish this now by using className property which now accepts a function and passes an isActive boolean property, like this:
<NavLink
to="users"
className={({ isActive }) => (isActive ? 'active' : 'inactive')}
>
Users
</NavLink>
You can also add multiple classes too, since v6 is out:
<NavLink
to="users"
className={({ isActive }) =>
isActive ? 'bg-green-500 font-bold' : 'bg-red-500 font-thin'
}
>
Users
</NavLink>
Demo: Active NavLink Classes with React Router
All still works the same. However, react-router-dom v4 replace Link with NavLink
import { NavLink as Link } from 'react-router-dom'; is also fine. Note: Navlinks by default is active so you can style a:active or activeStyle={{color: 'red'}}
Expanding on #agm1984's answer:
The solution of NavLinks is not updating styles correctly, which was using routerReducer from react-router-redux, has not worked for me. Instead, I found out that the issue was that connect wrapper uses shouldComponentUpdate and prevented rerendering of the component containing NavLinks.
Correct solution in my situation was to pass options object to connect as 4th parameter as shown below:
export default connect(mapStateToProps, null, null, { pure: false })(NavItems);
This example from the react-router v4 custom link documentation will help you to accomplish it:
const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => (
<Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
<div className={match ? 'active' : ''}>
{match ? '> ' : ''}<Link to={to}>{label}</Link>
</div>
)}/>
);
So in your case you could create following component:
const CustomLink = ({ activeStyle, children, className, to, activeOnlyWhenExact }) => (
<Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
<Link to={to} className={className} style={match && activeStyle}>{children}</Link>
)}/>
);
And then use it like:
<div id="tags-container">
{tags.map(t =>
<CustomLink
className="tags"
activeStyle={{ color: 'red' }}
to={t.path}
>
{t.title}
</CustomLink>
)}
</div>
Related
Im having a problem on implementing dimmed content on semantic ui react sidebar on nextjs...
This is the dimmed content on semantic ui
https://react.semantic-ui.com/modules/sidebar/#states-dimmed
this is my layout code:
import React, { useState } from 'react';
import CartSidebar from './CartSidebar';
import Navbar from './Navbar';
const StoreLayout = ({ children }) => {
const [toggleCart, setToggleCart] = useState(false);
function toggleMenuCart() {
setToggleCart(!toggleCart);
}
return (
<>
<CartSidebar toggleMenu={toggleCart} />
<Navbar onToggleMenuCart={toggleMenuCart} />
{children}
</>
);
};
export default StoreLayout;
this is my navbar code:
<nav>
<div className="borderLeftList">
<li className="cart">
<Button
onClick={props.onToggleMenuCart}
className="cart-icon empty"
/>
</li>
</div>
</nav>
this is my sidebar code:
import React, { useState } from 'react';
import cn from 'classnames';
import { Icon, Menu } from 'semantic-ui-react';
import Link from 'next/link';
export default function CartSidebar(props) {
const classes = cn(
'ui',
'sidebar',
'push',
'right',
'inverted',
'menu',
'vertical',
'animating',
{ visible: props.toggleMenu }
);
return (
<div className={classes}>
<Menu.Item as={Link} href="/admin">
<a>
<i className="fa fa-home" />
Dashboard
</a>
</Menu.Item>
<Menu.Item as={Link} href="/admin/orders">
Second Menu
</Menu.Item>
<Menu.Item as={Link} href="/admin/products">
Third Menu
</Menu.Item>
</div>
);
}
this is my _app.js code:
<StoreLayout>
<Component {...pageProps} />
</StoreLayout>
if you need any more details you can ask on the comment... Thank you so much in advance!!! :)
The documentation shows it will dim all of its children:
<Dimmer active={true} page>
<ChildComponent/>
</Dimmer>
Which will then dim the child component. Along with that you can also specify properties like "page" to tell it to dim the whole page.
If you're trying to use it with sidebar, then you have to wrap the content for sidebar in a dimmer.
const Page = () => {
const [active, setActive] = useState(false)
return <div>
<Sidebar setActive={setActive}/>
<Dimmer active={active} page> // this is a child
<Content/>
</Dimmer>
</div>
}
Then in the sidebar you'll have to set the active when you click an item or whatever. This example isn't perfect, just gives you a rough idea of what you can do.
Alternatively:
.dimmed {
background: black;
opacity: 0.5;
}
You can also just do it yourself and apply a class with opacity to whatever needs to be dimmed.
CREDITS ON #Matriarx for giving me idea on how to answer his question...
You have to import the Dimmer on sematic-ui-react and then parent the child using this code:
<Dimmer.Dimmable dimmed={toggleCart}>
<Dimmer
className="dimmedContent"
active={toggleCart}
onClickOutside={handleHide}
/>
put this on your css so that you can give yourself a style, without this css you cant make the dimmed fullscreen
.dimmedContent {
display: block !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
background: rgba(0, 0, 0, 0.25) !important;
cursor: default !important;
z-index: 8 !important;
}
this is the full code:
import React, { useState } from 'react';
import { Dimmer } from 'semantic-ui-react';
import CartSidebar from './CartSidebar';
import Navbar from './Navbar';
const StoreLayout = ({ children }) => {
const [toggleCart, setToggleCart] = useState(false);
function toggleMenuCart() {
setToggleCart(!toggleCart);
}
const handleHide = () => {
setToggleCart({ active: false });
};
return (
<>
<Dimmer.Dimmable dimmed={toggleCart}>
<Dimmer
className="dimmedContent"
active={toggleCart}
onClickOutside={handleHide}
/>
<CartSidebar toggleMenu={toggleCart} />
<Navbar onToggleMenuCart={toggleMenuCart} />
{children}
</Dimmer.Dimmable>
</>
);
};
export default StoreLayout;
also dont forget to put the css that i provided above :)
Cheers!
I want to implement a color option in my button components to use it in all my global components so I can change the text and color Dynamically
is it correct?
import React from 'react';
import './Button.css';
const Button = ({text, BtnVersion1}) => {
return (
{text}
)
}
export default Button;
<Button style={{color: "red"}} text="SHOP NOW" />
Your component code seems to be fully correct. But when using your component you have to pass props this way:
<Button text={"SHOP NOW"} BtnVersion1={"red"} />
This is where styled components can be very useful. Where you're declaring 'style' on the component, that is an inline style and would only exist on that instance of the button. You can pass a prop, say 'btnColor' to the button which is used by the styled component to change the color. See below.
import React from 'react';
import styled from 'styled-component';
import './Button.css';
const StyledButton = styled.a`
background-color: ${props => props.btnColor ? props.btnColor : 'red'};
`
const Button = ({
text,
btnColor
}) => {
return (
<StyledButton href="#" btnColor={btnColor} className="buy">{text}</StyledButton>
)
}
export default Button;
<Button btnColor='red' text="SHOP NOW" />
You can see above in the StyledButton that if we provide the btnColor prop than use that color, else default to 'red.'
For more information on styled components - https://styled-components.com/
You can have a more "dynamic" way of doing it (so your instance of <Button> doesn't change):
import React from 'react';
import './Button.css';
const Button = ({ text, style }) => {
return (
{text}
)
}
export default Button;
<Button style={{ color: "red" }} text="SHOP NOW" />
If you want to just control the color (or other properties) you can do something like:
import React from 'react';
import './Button.css';
const Button = ({ text, color }) => {
return (
{text}
)
}
export default Button;
<Button color="red" text="SHOP NOW" />
You might want to use your component this way:
The advantage here is that you can pass all your custom styles for every single one of your buttons.
const Button = ({text, style}) => {
return (
{text}
);
};
ReactDOM.render(<Button style={{color: "red"}} text="SHOP NOW" />, document.querySelector("#root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root">
<!-- Your root container -->
</div>
Donot use anchor tag as a button in react , If you want to know the reason read this doc
https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-is-valid.md
I think best way to style a button is using styled component , I have given an example code in this sandbox , you can pass props for things only you want to change like for background, if no value is given it will take default color
try it
code :
import "./styles.css";
import styled from "styled-components";
const Button = styled.button`
font-family: "Work Sans", sans-serif;
font-size: 14px;
font-weight: 600;
color: #ffffff;
line-height: 16px;
background: ${(props) => (props.background ? props.background : "#00D2AD")};
transition: all 0.4s ease-out;
transition: all 0.4s ease-out;
padding: 14px 24px;
outline: none;
text-align: center;
display: inline-block;
border: none;
cursor: pointer;
border-radius: 4px;
`;
export default function App() {
return (
<div className="App">
<Button>Default Button </Button>
<br />
<br />
<Button background={"gray"}>Custom Button</Button>
</div>
);
}
I'm new to styling in React. I tried CSS modules and styled components but I'm not able to change layout and styles.
The goal is to have a group of buttons to display as flex on the main page and as an inline with different style attributes in another page by re-using the HomeButtons.js component.
HomeButtons.js is the home page and it has a map() function looping through a button called ButtonCategory.js.
HomeButtons.js renders the map() inside a styled using CSS modules file. ButtonCategory is styled with a CSS modules file as well.
HomeButtons.js is then returned inside a in another class Component called CardsCategory.js. It is in this component that I'm trying to change the display and styl... With a styled Component on the I can show a border but the display attribute doesn't works.With CardsCategory.module.css I can't change the display either...
Not sure what to do... How to change the layout of the re-used component and the style of its nested button component ?
Any feedback is welcome!
HomeButtons.js
import React, { Component } from 'react'
import classes from './HomeButtons.module.css';
import ButtonCategory from '../../components/ButtonCategory/ButtonCategory'
class HomeButtons extends Component {
handleClick = (buttonValue) => {
buttonValue = buttonValue.slice(0, 3).toLowerCase();
this.props.history.push("/" + buttonValue);
};
render() {
const allCategoriesButtons = ["Physics", "Chemistry", "Medicine", "Literature", "Peace", "Economics"];
const allCatMap = allCategoriesButtons.map(button =>
< ButtonCategory
key={button.toString()}
value={button}
name={button}
onClick={e => this.handleClick(e.target.value)}
/>
)
return (
<div>
<div className={classes.container__section}>
{allCatMap}
</div >
</div>
)
}
}
export default HomeButtons;
HomeButtons.module.css
.container__section {
display: flex;
flex-flow: row wrap;
margin: auto;
align-items: center;
justify-content: space-around;
}
ButtonCategory
import React from 'react'
import classes from './ButtonCategory.module.css';
function buttonCategory(props) {
return (
<button
className={classes.b}
name={props.name}
onClick={props.onClick}
value={props.value}
>
{props.name}
</button>
)
}
export default buttonCategory;
ButtonCategory.module.css
opacity: 0.5;
color: red;
font-size: 2em;
margin: 10px 20px 10px 20px;
flex: 1 400px;
height: 3em;
}
CardsCategory
import React, { Component } from 'react';
import axios from 'axios';
import classes from './CardsCategory.module.css';
import HomeButtons from "../HomeButtons/HomeButtons"
import styled from 'styled-components';
const StyledDiv = styled.div`
border: 10px solid orange;
//display: inline; //NOT working
`
class Cards extends Component {
render() {
return (
<div>
<StyledDiv>
<HomeButtons className={classes.test}/>
</StyledDiv>
</div>
)
}
}
export default Cards;
CardsCategory.module.css
.test {
display: inline;
}
You can send styles thru the props and in the component set them as your styles ex.
<MyComponent textAlign='center' ...>
in MyComponent component
<div style={{textAlign: this.props.textAlign}}>
...
</div>
or send whole styles as objects ex.
render(){
const stl = {textAlign: 'center',width:'500px'};
return(
<MyComponent wholeStyle={stl}/>
)
}
and in MyComponent
<div style={this.props.wholeStyle}>
...
</div>
They are 3 ways you can style through props
You can pass an entire style object
Eg:
<MappedComponent style={'display':'flex','alignItems':'center'} />
In the mapped component
Function MappedComponent ({style}){
return (
What's popaining !
);
}
You can style by passing in the specific style you want
Eg:
<MappedComponent textAlign={'center'} />
In the mapped component
Function MappedComponent ({textAlign}){
return (
What's popaining !
);
}
The third way you can style is by defining styles in a CSS file and just passing in the class name
Eg:
<MappedComponent className={''flex-button-style'} />
In the mapped component
Function MappedComponent ({className}){
return (
What's popaining !
);
}
Pick what works best for you and stay consistent with it :) .
I am dealing with 2 components:
header.js and footer.js.
I also have 2 css files:
header.module.css and footer.module.css.
Both of them use different styling for the a tag.
I import the respective CSS files within each js file, but the a styling in footer.module.css seems to overtake the styling in header.js even though it wasn't imported.
Here is the code:
header.js
import React from "react"
import { Link } from "gatsby"
import "../styles/header.module.css";
const ListLink = props => (
<li style={{display: `inline-block`, marginRight: `1rem`, fontSize: '1.15rem', fontWeight: 'bold'}}>
<Link className="link" to={props.to}>{props.children}</Link>
</li>
)
footer.js
import React from "react"
import "../styles/footer.module.css";
const FooterLink = props => (
<li style={{ display: `inline-block`, marginRight: `1rem`, marginBottom:'0rem', fontSize: '1.05rem', fontWeight: 'bold'}}>
{props.children}
</li>
)
header.module.css
a {
color: var(--textLink);
text-shadow: var(--textShadow);
transition:.2s;
background-image: var(--bgimage);
}
a:hover {
color: #da1e11;
background-image: none;
}
footer.module.css
a{
color: var(--textLink);
text-shadow: var(--textShadow);
transition:.2s;
background-image: none;
}
a:hover {
color: #da1e11;
background-image: none;
}
The background-image property from footer overtakes the one specified in header.
If you are using Gatsby's default <Layout>, it shares <Header> and <Footer> components so, both are loading each CSS in each page as you can see here:
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div>
<main>{children}</main>
<Footer>
© {new Date().getFullYear()}, Built with
{` `}
Gatsby
</Footer>
</div>
</>
)
}
The easiest solution is to wrap the each component in a class to make the CSS only available inside that class, something like this:
import React from "react"
import { Link } from "gatsby"
import "../styles/header.module.css";
const ListLink = props => (
<li className="list__item">
<Link className="link" to={props.to}>{props.children}</Link>
</li>
)
Note: you can even wrap the <Link> inside a <div> for example.
I would suggest removing inline styles if you are using CSS modules to avoid mixing styles and improve readability.
The same applies for the <Footer> component.
According to the documentation it's import something from './something.module.css' and then <Component className={something.error}
First: I know there are already a couple of questions about this error, but they had a different source (I think). Here's my code:
<BrowserRouter>
<React.Fragment>
<Navbar className='navbar_all'>
<Navbar.Header>
<Navbar.Brand>
<Link className='navbar_brand' id='home' to='/'>
<img alt='ZdajTo' src="assets/images/new_logo.png" style={{height: '30px'}}/>
</Link>
</Navbar.Brand>
</Navbar.Header>
<Nav className='float_right'>
<Link to='/homepage' style={{textDecoration: 'none'}}>
{/*^^^^^^^^^^^^ This line throws an error*/}
<button style={{
backgroundColor: '#F16049',
border: '4px solid #F16049',
borderRadius: '4px',
padding: '10px',
marginBottom: '5px',
color: '#fff'
}}>
DLA ROZWIĄZUJĄCYCH
</button>
</Link>
</Nav>
</Navbar>
</React.Fragment>
</BrowserRouter>
The error I'm getting is this:
Warning: React does not recognize the activeKey prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase activekey instead. If you accidentally passed it from a parent component, remove it from the DOM element.
The problem is, I believe in the nesting, but I have no idea what can be wrong here.
Any ideas?
The issue is that you should not nest DOM elements directly under Nav component, instead use NavItem. Problem with such approach is that NavItem is anchor and nesting Link under it will throw another error, since Link is also an anchor.
Solution is to use LinkContainer from react-router-bootstrap like this.
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Nav, NavItem, Navbar } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';
const app = (
<BrowserRouter>
<Navbar>
<Nav>
<LinkContainer to="/somewhere">
<NavItem>somewhere</NavItem>
</LinkContainer>
</Nav>
</Navbar>
</BrowserRouter>
);
ReactDOM.render(app, document.getElementById('root'));