styled component doesn't work with hierachy selectors - css

I'm learning to use styled components,but it looks like when i target css classes in hierarchy,it doesn't seem to work.Here i'm using i would like to make apply some styles wheneve use hovers on navigations links.
Here is my navbar code :
import React from "react";
import { Nav, Navbar } from "react-bootstrap";
import Flag from "../common/Image";
import styled from "styled-components";
import NavLink from "../common/NavLink";
const imageURL = "/static/img/abc.png";
const Navigation = ({ className }) => {
return (
<Navbar className={className} collapseOnSelect expand="lg" variant="light">
<Navbar.Brand href="#home">
<Flag imageSource={imageURL} size={[80, 70]} />
</Navbar.Brand>
<NavLink linkName="A" URL={"#"} />
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<NavLink linkName="B" URL={"#a"} />
<NavLink linkName="C" URL={"#b"} />
<NavLink linkName="D" URL={"#b"} />
</Nav>
<Nav>
<NavLink linkName="Espace de discussion" URL={"#discussions"} />
<NavLink linkName="Contactez-nous" URL={"#contact"} />
<Nav.Link>
<i clasName="fas fa-envelope" />
</Nav.Link>
<Nav.Link>
<i className="fas fa-bell" />
</Nav.Link>
<Nav.Link>
<i className="fas fa-user-circle" />
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
};
export default styled(Navigation)`
background-color: white;
border-bottom: 1px solid #e4e8f0;
`;
And my NavLink component
import React from "react";
import styled from "styled-components";
import { Nav } from "react-bootstrap";
import PropTypes from "prop-types";
const NavLink = ({ linkName, URL, className }) => {
return (
<Nav.Link className={className} href={URL}>
{linkName}
</Nav.Link>
);
};
NavLink.PropTypes = {
linkName: PropTypes.string,
URL: PropTypes.string
};
export default styled(NavLink)`
cursor: pointer;
color: green;
transition: 0.4s linear;
padding: 10px;
&:hover {
color: white;
font-size: 90;
background-color: #2e384d;
border-radius: 10px;
}
.navbar-light .navbar-nav .nav-link &:hover {
color: white;
}
`;
I the bellow gif,the animation is for changind links styled is working for all the links,but the color is only changing to white for the A link.But the form other background,border are changing but not the link color.Here the behaviour:
When i use the following code : .navbar-light .navbar-nav .nav-link &:hover {
color: white;
} in a normal css file without using styled component i get the good the exptected behavior.For solving i tried to use sass way of doing in the definition of my styled component like this :
.navbar-light {
.navbar-nav {
.nav-link {
&:hover {
color: white;
}
}
}
}
But nothing changes.How can i do for making all links text become white with styled-compont definition?

Alright, because of how <Nav> is wrapping your <NavLink>, the nav-link className has a higher specificity than your styled component className (the NavLink component is applying the styled component className before "nav-link" and, as a result, doesn't override the Bootstrap CSS). For example, the className looks like: "sc-lhVmIH gcJAof nav-link", where the styled component className: "sc-lhVmIH gcJAof" is being overridden by the last applied className "nav-link". There are several solutions to fix this, as shown below.
Solutions
Simply add color: white !important; in the styled NavLink:
export default styled(NavLink)`
cursor: pointer;
color: green;
transition: 0.4s linear;
padding: 10px;
border-radius: 10px;
&:hover {
color: white !important;
font-size: 90;
background-color: #2e384d;
border-radius: 10px;
}
`;
In Navigation, where <NavBar className={className}>...</NavBar> accepts a styled component className, add the following css to override the Bootstrap CSS stylesheet:
export default styled(Navigation)`
background-color: white;
border-bottom: 1px solid #e4e8f0;
&.navbar-light {
& .navbar-nav {
& .nav-link:hover {
color: white;
}
}
}
`;
Import the Bootstrap less into a less file and override the nav-link:hover className.
CSS Specificity
Here's how the CSS specificity is being applied to the DOM:
Demos
Click here for a working demo.
Working codesandbox (contains solution #1 and #2 -- you'll only need to use one of them, not both):

Related

Access other className on hover in emotion css

I use EmotionCSS. I want to get an access to other className while catching focus on another. For example I have a component like that:
<div className={styles.root}>
<input className={styles.input} ... />
<div/>
The style file looks like that:
import { css } from '#emotion/css';
export const styles = {
root: css`
border: 1px solid black;
`
input: css`
...
&:focus {
// Here I want to access 'root' className and change its colour. Is it possible?
}
`,
}
You can try to use the :has() pseudo-class on the root to change the focus styles in input tag.
import { css } from "#emotion/css";
export const styles = {
root: css`
border: 3px solid black;
&:has(input:focus) {
border-color: red;
}
`,
input: css`
font-size: 1.5rem;
&:focus {
text-transform: uppercase;
}
`
};
export default function App() {
return (
<div className="App">
<div className={styles.root}>
<input type="text" className={styles.input} />
</div>
</div>
);
}

How do I reference another component's styled-components generated className while creating a (hover) rule in a different component?

I'm creating a menu with styled-components and React, and want the color of the icon to change on hover, but I need it to change when the icon's parent is hovered, so that hovering the text next to the icon also activates the icon's hover styles. Here is the code I'm using to get close:
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
const Menu = styled.div`
display: flex;
flex-direction: column;
`;
const LinkContainer = styled.div`
display: flex;
flex-direction: row;
`;
const FontAwesomeIconExtended = styled.div`
flex: 1;
display: grid;
place-items: center;
height: 40px;
width: 40px;
padding: 10px 2px;
border-radius: 10px;
transition: color 0.5s ease;
color: ${(props) => (props.$isactive ? '#fff' : '#CBE3EB')};
background: ${(props) =>
props.$isactive
? 'linear-gradient(96.34deg, #004157 0%, #0090b2 100%)'
: '#fff'};
${LinkContainer}:hover & {
color: ${(props) => (props.$isactive ? '#fff' : 'green')};
} /* Problem occurring here */
`;
const LinkText = styled.div`
flex: 1 0 100px;
`;
function NavLink({ ...props }) {
return (
<Link to={props.path}>
<LinkContainer $isactive={props.$isactive}>
<FontAwesomeIconExtended
$isactive={props.$isactive}
icon={props.icon}
size='2x'
as={FontAwesomeIcon}
/>
<LinkText $isactive={props.$isactive}>{props.name}</LinkText>
</LinkContainer>
</Link>
);
}
export default function NavMenu() {
return (
<Menu>
<NavLink path='/' name='Home' icon='house' $isactive />
<NavLink path='/profile' name='Profile' icon='user' />
<NavLink path='/payments' name='Payments' icon='credit-card-front' />
<NavLink path='/contracts' name='Contracts' icon='file-contract' />
<NavLink path='/messages' name='Messages' icon='mail-bulk' />
<NavLink path='/messages' name='Documents' icon='folders' />
<NavLink path='/locations' name='Transfer' icon='truck-moving' />
</Menu>
);
}
The way you reference another styled component in a later component is very clever, but in this case when it creates the hover rule, it creates without consideration of the different type of parent container ($isactive === true, or $isactive === false), so all LinkContainers have two rules for hovering, and use the last defined rule. This can be seen by moving $isactive to the last NavLink component.
Here is a screenshot of the devtools showing what I mean about the two hover rules not taking into consideration the parents class, just the general type of the parent.
I think the solution might involve being specific about the two types of LinkContainer's classNames while creating the hover rule, but that doesn't seem well supported. Thanks for taking a look.
Increase the specificity by repeating the class name, using another '&'
${LinkContainer}:hover && {

When reusing component, my CSS doesn't get applied to it

I am trying to figure out how something like this might occur. Bear with me, since the details might be a little bit sloppy.
I have a Header Component which simply takes up all the viewport, and then adds a NavigationBar Component. The Header Component works just fine in the other place I used it, but for some reason, when I tried reusing it just now, the NavigationBar inside it gets funky (all CSS is simply gone).
Here is the Header component that has the following styling (which works btw): {position: relative;
height: 100vh;
width: 100%;}
import React from "react";
import NavigationBar from "../NavigationBar/NavigationBar";
import "./Header.css";
const Header = (props) => (
<div className="blog-header">
<NavigationBar />
{props.children}
</div>
);
export default Header;
My NavigationBar is a simple React-Bootstrap Navbar (I have decided to delete what was inside navigationItems because I don't think those matter to the problem at hand):
import React from "react";
import { Container, Navbar, Nav, NavbarBrand } from "react-bootstrap";
import Logo from "../Logo/Logo";
import "./NavigationBar.css";
const navigationItems = []
const NavigationBar = (props) => (
<Container>
<Navbar id="navigation" bg="transparent" variant="dark" expand="lg">
<div className="div-brand d-flex flex-grow-1">
<NavbarBrand href="/">
<Logo />
</NavbarBrand>
<div className="w-100 text-right">
<Navbar.Toggle data-toggle="collapse" data-target="#da-navbarNav">
<span className="navbar-toggler-icon"></span>
</Navbar.Toggle>
</div>
</div>
<Navbar.Collapse
className="text-uppercase flex-grow-1 text-right"
id="da-navbarNav"
>
<Nav className="ml-auto flex-nowrap">
{navigationItems.map((navItem, index) => {
return (
<Nav.Item key={index}>
<Nav.Link
id={navItem.id ? navItem.id : null}
href={navItem.path}
className={navItem.classes.join(" ")}
onClick={(event) =>
props.navItemClick(event, window.location.pathname, navItem)
}
>
{navItem.placeholder}
</Nav.Link>
</Nav.Item>
);
})}
</Nav>
</Navbar.Collapse>
</Navbar>
</Container>
);
Navbar.css code:
#navigation {
z-index: 10;
}
#navigation .div-brand {
align-items: center;
}
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 0.75);
letter-spacing: 1px;
font-size: 0.95rem;
font-weight: bold;
line-height: 24px;
width: 6.4rem;
text-align: center;
}
.navbar-dark .navbar-nav .nav-link:hover,
.navbar-dark .navbar-nav .nav-link:active {
color: #da3833;
}
.navbar-dark #btn-contact {
background-color: #da3833;
border-radius: 3px;
text-align: center !important;
}
.navbar-dark #btn-contact:hover,
.navbar-dark #btn-contact:active {
color: white !important;
}
#media (max-width: 992px) {
.navbar-dark .navbar-nav .nav-link {
text-align: right;
margin-top: 0.2rem;
margin-left: auto;
}
.navbar-dark .navbar-nav .nav-item {
text-align: right;
width: 100%;
}
.navbar-toggler {
outline: none !important;
}
}
I'm currently reusing it inside this component that has as styling the following:
.article-header {
height: inherit;
width: inherit;
position: absolute;
top: 0;
}
import React, { useState, useEffect, useCallback } from "react";
import Header from "../../../components/Header/Header";
import "./ArticlePage.css";
const ArticlePage = (props) => {
const [id, setId] = useState(null);
const loadQueryParams = useCallback(() => {
setId(props.match.params.id ? props.match.params.id : null);
}, []);
useEffect(() => loadQueryParams(), [loadQueryParams]);
return (
<div>
<Header>
<div
className="article-header"
style={{ backgroundColor: "black", opacity: "0.2" }}
>
{id}
</div>
</Header>
</div>
);
};
export default ArticlePage;
If you might have an idea where this might go wrong, feel free to answer. I'm also gonna leave here how the navigationbar should look, and how it rendered.
If you need any more info or details please announce me! Thank you!
EDIT: as requested, here is a demo
I managed to solve it. The problem was that my "bootstrap.css" folder that contains my bootstrap theme was not being imported globally in "index.js", and instead it was inside "index.html".
To be noted: I was also using a Router to go to this new Component in which I was using Navbar, and since the css files weren't imported globally, the css wasn't there.

Emotion styled components not applying rules

I'm trying to use emotion.
My .js code is:
import React from 'react';
import { css } from '#emotion/core';
export const Menu = () => (
<>
<nav
css={css`
position: absolute;
color: white;
`}
>
<h1
css={css`
color: white;
`}
>
Title
</h1>
<ul>
<li>Proyectos</li>
<li>Blog</li>
<li>Acerca</li>
<li>Contacto</li>
</ul>
</nav>
</>
);
export default Menu;
When inspecting the element, I get this instead:
You have tried to stringify object returned from css function. It isn't supposed to be used directly (e.g. as value of the className prop), but rather handed to emotion so it can handle it (e.g. as value of css prop).
Use JSX Pragma with jsx function from '#emotion/react'. This allow use css prop.
Docs: https://emotion.sh/docs/css-prop#jsx-pragma
/** #jsx jsx */
import { jsx } from '#emotion/react'
import { css } from '#emotion/core'
const App = () => (
<nav
css={css`
position: absolute;
color: white;
`}
>
<h1
css={css`
color: white;
`}
>
Title
</h1>
<ul>
<li>Proyectos</li>
<li>Blog</li>
<li>Acerca</li>
<li>Contacto</li>
</ul>
</nav>
)

How to remove the text decoration of React Link?

I am using React and react-router-doms Link component to navigate between pages.
But I am struggling with removing the text-decoration in the component.
React:
<Link className="nav-link" to="/page">LINK</Link>
CSS:
.nav-link {
text-decoration: none;
}
This CSS does not seem to work, but when I replace the Link to a a component it works fine.
<a className="nav-link" href="/page">LINK</a>
Anyone has an idea how to remove the text-decoration from a Link component?
If react-router is less than v4
Try inline style
<Link to="first" style={{ textDecoration: 'none' }}>
Link
</Link>
If you want to use styled-components, you could do something like this:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
const StyledLink = styled(Link)`
text-decoration: none;
&:focus, &:hover, &:visited, &:link, &:active {
text-decoration: none;
}
`;
export default (props) => <StyledLink {...props} />;
OR
You can do it with NavLink in react-router v4
<NavLink
className="tags"
activeStyle={{ color: 'red' }}
to={'/page'}
>
LINK
</NavLink>

Resources