Emotion styled components not applying rules - css

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>
)

Related

Css module in React component

Having this css module:
mymodule.module.css:
ol li:not(:last-child)::after {
color: red;
margin: 1px;
}
React component:
import myStyles from './mymodule.module.css';
...
export const MyComponent: React.FunctionComponent<MyComponentProps> = ({...} => {
...
return (
<li className={myStyles}>
...
</li>
);
There is a red line under className word which when hover states:
Type '{ readonly [key: string]: string; }' is not assignable to type
'string'.ts(2322) index.d.ts(1749, 9): The expected type comes from
property 'className' which is declared here on type
'DetailedHTMLProps<LiHTMLAttributes, HTMLLIElement>'
Any suggestions?
Your CSS file:
# Add your default tag styles
ol li:not(:last-child)::after {
color: red;
margin: 1px;
}
# Add your class
.my-class {
margin: 1rem;
}
Your TSX
// import your stylesheet
import './mymodule.module.css';
...
export const MyComponent: React.FunctionComponent<MyComponentProps> =
({...}) => {
...
// use the class as you would in HTML
return (
<li className="my-class">
...
</li>
);
}
Class Name property is for assigning specific class defined in your css file if you want to apply css on li tag, you just need to import css file in ts file or if you want to give it a styling with class name, you should give its a parent a class like this:
React component:
<ol className={myStyles.abc}
<li>
...
</li>
</ol>
mymodule.module.css:
.abc li:not(:last-child)::after {
color: red;
margin: 1px;
}

Styled components, two layers of className - How would I apply style in component declaration?

I have created a Container component with component styles in next.js.
When I declare use of this container component throughout my site, I would like to add a className to it and subjectively style it depending on the context of its use.
Here is an example of my Container component:
const Container = (props) => (
<>
<div className="container">
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
So, I want to give it a maximum width of 1200px, and centre it with auto margins. No problem, I have done that.
Now, I am planning to use this component in the header of my site. But in the case of the header, I would like the Container component to be a flexbox:
import Container from './Container'
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
{/* Navigation items */}
</ul>
</nav>
</Container>
</header>
<style jsx>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
When I view the site, I noticed the flexbox style I specified for the Container component in the header is not present.
I was expecting the className to take effect, and allow me to add additional styles.
I believe this has something to do with it thinking that className is not a class name, rather props. But, I want to keep my code dry by creating style inheritance on components.
How could I do this?
Thanks for the help!
This is a job for styled components:
import React from "react";
import styled from "styled-components";
export default function App() {
return (
<>
<Container custom={"header"}>
<h1>Very fancy h1 with flex display</h1>
</Container>
<Container custom={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => (props.custom === "header" ? "flex" : "block")};
/* you can call your prop ^^^^^^ whatever you want,
just change it on the container element too*/
& h1 {
/* you can apply css to children like so */
font-family: ${(props) =>
props.custom === "header"
? '"Courier New", Courier, monospace'
: '"Arial Black", Gadget, sans-serif'};
}
`;
In the above, I've created a custom styled component that receives the custom prop and then conditionally changes the values you are looking to adjust. To make the changes more visible to the eye, I've also styled the font so you can see the immediate difference between the two <Container> elements.
For a solution that is more scalable (e.g., for different themes), use ThemeProvider:
import React from "react";
import styled, { ThemeProvider } from "styled-components";
export default function App() {
return (
<>
<ThemeProvider theme={ContainerHeader}>
<Container>
<h1>Very fancy h1 with flex display</h1>
</Container>
</ThemeProvider>
<Container theme={"regular"}>
<h1>Non-fancy h1 with no flex display</h1>
</Container>
</>
);
}
const Container = styled.div`
display: ${(props) => props.theme.display};
& h1 {
font-family: ${(props) => props.theme.h1Font};
}
`;
Container.defaultProps = {
theme: {
display: "block",
h1Font: '"Arial Black", Gadget, sans-serif'
}
};
const ContainerHeader = {
display: "flex",
h1Font: '"Courier New", Courier, monospace'
};
CodeSandbox: https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773
I believe I have found the answer to my own question (I will still leave this question open for a couple more days just in case it can be improved).
In order to pass styles, you can add the "global" flag to the styled JSX and append additional classnames in the component with props.className.
Parent Container component using props.className:
const Container = (props) => (
<>
<div className={`container ${props.className}`}>
{props.children}
</div>
<style jsx>{`
.container{
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
`}</style>
</>
)
export default Container;
Then, when you want to use that component, you can add additional styles with the global flag in the <style jsx>:
Container being used and styled even more in the header:
import Container from './Container';
const Header = (props) => (
<>
<header>
<Container className="header-col">
<div>
<h1>{props.title}</h1>
</div>
<nav>
<ul>
<li>Hello</li>
<li>There</li>
</ul>
</nav>
</Container>
</header>
<style jsx global>{`
.header-col{
display: flex;
justify-content: space-between;
}
`}</style>
</>
)
export default Header;
This is not 100% perfect though (but in my opinion it is still pretty good):
The global flag makes your styles global. So other components can use
these styles (I believe)
You need to make sure your components take in props.className to append additional classnames for this global style

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.

styled component doesn't work with hierachy selectors

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):

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