I have been learning react styled component and now I am stuck at a point where I am trying to style the first and last child of styled Wrapper in react and my styled are not applying.
Need help in understanding why it is not working.
Below is the codesandbox link and my code.
https://codesandbox.io/s/target-first-child-css-styled-components-forked-9i65re
import ReactDOM from "react-dom";
import styled from "styled-components";
const Text = styled.div`
color: green;
font-size: 20px;
&:first-child {
color: red;
}
&:last-child {
color: blue;
}
`;
function App() {
return (
<Text>
<div>div1</div>
<div>div2</div>
<div>div3</div>
<div>div4</div>
</Text>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
this selectors means when the parent itself is the first child or the last child, in this case, it is both :D this is why it's blue, what you want to do is:
const Text = styled.div`
color: green;
font-size: 20px;
& div:first-child {
color: red;
}
& div:last-child {
color: blue;
}
`;
Which means when a child div is the first or the last
Add space between & and '*-child'.
Also if you have nested divs, they will be affected too...
https://styled-components.com/docs/basics#pseudoelements-pseudoselectors-and-nesting
Related
I have a component like this:
// MyComponent.tsx
export function MyComponent(): React.ReactElement {
return <Wrapper>
<Text>
hello there
</Text>
<AnotherText>
bye bye
</AnotherText>
</Wrapper>
}
export const Wrapper = styled.div`
color: #FEB240;
background: #f5f5f5;
padding-bottom: 5rem;
padding-left: 7rem;
padding-right: 7rem;
gap: 2rem;
`;
export const Text = styled.span`
width: 50%;
cursor: pointer;
color: rgba(28, 33, 120, 1);
`;
export const AnotherText = styled.span`
color: red;
`;
I want to be able to style the wrapper. I tried to like this (from this answer Styling Nested Components in Styled-Components), but I don't see any change:
// AnotherPlace.tsx
const NewlyStyledMyComponent = styled(MyComponent)`
${Wrapper} {
color: brown;
background: magenta;
}
`;
It seems that MyComponent also need to take (generated) className as props and assign it to the root wrapping element to make the nested styles to work as expected.
Simplified live demo: stackblitz
A basic example in MyComponent:
import styled from 'styled-components';
interface Props {
className?: string;
}
export const Wrapper = styled.div`
background-color: hotpink;
`;
export const Text = styled.span`
color: #fff;
`;
function MyComponent({ className }: Props) {
return (
<div className={className}>
<Wrapper>
<Text>Hello</Text>
</Wrapper>
</div>
);
}
export default MyComponent;
And at where it is imported and used:
import styled from 'styled-components';
import MyComponent, { Wrapper, Text } from './MyComponent';
const NewlyStyledMyComponent = styled(MyComponent)`
margin-bottom: 7px;
${Wrapper} {
background-color: indigo;
}
${Text} {
color: gold;
}
`;
function App() {
return (
<div>
<NewlyStyledMyComponent />
<MyComponent />
</div>
);
}
export default App;
There are indeed 2 issues:
To style a custom React component (even just so that its nested components can be styled), you always need to take a className prop and to apply it on one of your rendered elements, as explained in styled-components docs:
The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.
To style nested components, the className of the parent element must be applied on a parent DOM element as well; that is why JohnLi's answer has to add an extra <div className={className}> around the <Wrapper>.
But in your case, you could just style MyComponent and apply the className on the <Wrapper>:
export function MyComponent({
className
}: {
className?: string;
}): React.ReactElement {
return (
// Apply className directly on the Wrapper
<Wrapper className={className}>
This text can be re-colored
<Text>hello there can be re-colored if styling nested Text</Text>
<AnotherText>bye bye</AnotherText>
</Wrapper>
);
}
const NewlyStyledMyComponent = styled(MyComponent)`
/* Directly style MyComponent */
color: brown;
background: magenta;
/* Styling of nested components */
${Text} {
color: white;
}
`;
Demo: https://codesandbox.io/s/vibrant-worker-05xmil?file=/src/App.tsx
There is a checkbox component:
import React, { InputHTMLAttributes } from "react";
import styled, { css } from "styled-components";
export const CheckBox: React.FC<InputHTMLAttributes<HTMLInputElement>> = (
props
) => {
return <Input type="checkbox" {...props} />;
};
const Input = styled.input`
${({ theme }) => css`
border: 1px solid white;
&:checked {
background-color: green;
border-color: green;
}
`}
`;
I want to set its checked color to another but doesn't work. It's still the default blue background color.
I hope:
Before
After
You can create own your component for that but it takes a lot of time.
Checkout into sandbox
Currently trying (and failing) to learn React for a project, and not understanding why the header links appear after the image, if they're in the same wrapper. I made different components for different parts of the navbar, and made a different file for the Logo and NavLinks (each in its own section). Here's the code.
App.js
// Importing NavBar
import NavBar from './components/navbar/NavBar';
// Actual App function, has our code
function App() {
return (
<div className="App">
{/* Navbar Declaration, with statement of what links to add */}
<NavBar />
</div>
);
}
export default App;
NavBar.js
// Importing react
import React from "react";
// Importing styled to be able to style the page
import styled from "styled-components";
// Importing the logo
import Logo from "../logo/Logo";
// Importing the links
import NavLinks from "./NavLinks.js";
// ---------------------------- Stylizing the navbar using styled-components
// Main Wrapper for Navbar
const Wrapper = styled.div`
width: 100%;
height: 10rem;
align-items: center;
padding: 0 1.5 rem;
transition: background-color .5s ease;
z-index: 9999;
border-bottom: 2px solid rgba(255,255,255,.05);
margin-left: 50px;
margin-right: 50px;
`;
// NavBar is separated into left, center and right
// Left side of Navbar
const LeftSide = styled.div`
display: flex;
`;
// Center of Navbar
// Flex is a way to define how much each portion is gonna take of the size given to it
const Center = styled.div`
display: flex;
`;
// Right side of Navbar
const RightSide = styled.div`
display: flex;
`;
// Declaration of navbar links
const navbarLinks = [
"Home Page",
"Illustrator Gallery",
"Art Gallery",
"Challenges"
];
/*const navbarLinks = [
{ title: `Home Page`, path: `/` },
{ title: `Illustrator Gallery`, path: `/illustrator-gallery` },
{ title: `Art Gallery`, path: `/art-gallery` },
{ title: `Challenges`, path: `/challenges` }
];*/
// ---------------------------- Creating the NavBar function/component
function NavBar(props) {
// Setting the return value, or the component
return(
<Wrapper>
{/* For the left side, we want to import the Logo component */}
<LeftSide>
<Logo />
</LeftSide>
<Center>
{/* For the middle, we want to add the different links */}
<NavLinks links={navbarLinks} />
</Center>
<RightSide></RightSide>
</Wrapper>
);
}
export default NavBar;
Logo.js
// Importing react
import React from 'react';
// Importing styled components
import styled from "styled-components";
// Importing the image
import USLogo from "../../assets/images/bunny.png"
// Styling the wrapper for the logo
const LogoWrapper = styled.div`
display: flex;
align-items: center;
`;
// Styling the actual logo, as well as its container
const LogoImg = styled.div`
width: 50px;
height: 50px;
img {
width: 100%;
height: 100%;
}
`;
// Styling the information next to the logo
const LogoText = styled.h2`
text-transform: uppercase;
font-size: 3rem;
font-weight: bold;
margin-left: 4px;
padding-top: 8px;
color: black;
`;
// Creating logo
function Logo(props) {
return(
// First we make the wrapper
<LogoWrapper>
{/* Inside the wrapper we'll have the image, then the text */}
<LogoImg><img src={USLogo} alt="US. logo"/></LogoImg>
<LogoText>US.</LogoText>
</LogoWrapper>
);
}
export default Logo;
NavLinks.js
// Importing react
import React from 'react';
// Importing styling
import styled from 'styled-components';
// Styling the container for the links
const LinksContainer = styled.div`
display: flex;
align-items: center;
`;
// Styling the ul components, or the menu
const LinksMenu = styled.ul`
display: inline-block;
text-transform: uppercase;
letter-spacing: 3px;
`;
// Styling each li
const LinksItem = styled.li`
display: inline-block;
vertical-align: top;
align-items: center;
justify-content: space-between;
margin-top: 15px;
padding: 0 1.1rem;
`;
// Styling each link
const Link = styled.a`
text-decoration: none;
color: black;
font-size: 1.6rem;
margin: 0 2rem;
position: relative;
&:hover{
color: rgb(24, 23, 23);
}
&::after {
content: '';
width: 100%;
height: 2px;
background-color: black;
left: 0;
bottom: -3px;
transform: scaleX(0);
transform-origin: left;
transition transform .5s ease;
}
&:hover::after{
transform: scaleX(1);
}
`;
// Creating the navigation links component
function NavLinks(props) {
return(
// First we do the container
<LinksContainer>
{/* Inside the container, we have the menu of links, then the li, and finally links */}
<LinksMenu>
{/* Each link Menu has a bunch of items, with each item having a link */}
{
props.links.map(
(label) => {
return(
<LinksItem><Link>{label}</Link></LinksItem>
)
}
)
}
</LinksMenu>
</LinksContainer>
);
}
export default NavLinks;
The result shows as follows:
Additionally, if I hover over the text, it doesn't change anything. In fact, it doesn't even add the little blue color indicating it's a link anymore. I'm not sure if this is a syntactical problem, since the same code works fine when using css.
I've checked other answers on here suggesting float: left and the like for the wrapper, but for some reason they don't work. Either I'm putting them in the wrong object, or they should be somewhere else.
Any help is appreciated!
I'm starting to work with react and have to build a clock component.
I want my parent div to have the same height as a child component. Why doesn't child height affect it's parent height?
HTML:
import React, { useState, useEffect } from "react";
import "./clock.scss";
export const Clock = () => {
let [date, setDate] = useState(new Date());
useEffect(() => {
let timer = setInterval(() => setDate(new Date()), 1000);
return function cleanup() {
clearInterval(timer);
};
});
return (
<div className="clock-wrapper">
<span className="test">
{date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
</span>
</div>
);
};
export default Clock;
SCSS (other components don't have css yet). Class "test" - green container. Class "clock-wrapper" - red container.
.dashboard {
display: flex;
justify-content: space-between;
padding: 25px 40px 25px 40px;
}
.clock-wrapper {
$_size-100: 100px;
}
.test {
color: $color-pickled-bluewood;
font-size: $_size-100;
font-weight: bold;
}
Image with current result. Red border is parent size. Green border with background color is children component.
Thanks for your help.
I've got a lot of table rows in my app. Some are links, some are not. Here is an example of one that is:
<tr [routerLink]="['/invoices', invoice?.invoice.id || 0, 'sms']">
I want to style all tr's with a routerLink like this:
tr[routerLink] {
cursor: pointer;
}
But it does not work. What is the correct CSS here? thanks
Use the compiled attribute ng-reflect-router-link : stackblitz
a[ng-reflect-router-link] {
color: red;
font-weight: 700;
}
tr[ng-reflect-router-link] {
cursor: pointer;
}
You can use a directive to add a class to every row with a routerLink attribute. Then style it in the css like normal.
import { Directive, HostBinding } from '#angular/core';
#Directive({
selector: 'tr[routerLink]'
})
export class ClickableTableRowDirective {
#HostBinding('class')
className = 'clickable-table-row';
constructor() {
}
}
.clickable-table-row {
cursor: pointer;
}
html:
<a [routerLink]='link' [ngClass]="{'router-link-active': true">{{name}}</a>
css:
.router-link-active {
cursor: pointer;
}
In your case the problem because of '[ ]' these brackets
so if you want to indentify which is the link and which is not then try below code
here's is example
<tr [routerLink]="['/invoices', invoice?.invoice.id || 0, 'sms']" routerLinkActive="active>
and in style.css
tr[routerLinkActive] {
color: red;
}
here is Stackblitz demo
this style only apply on those are links