React styled-components: refer to other components - reactjs

According to styled-components doc's I can refer to another component to trigger, for example, a hover effect.
const Link = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
`;
const Link2 = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: steelblue;
color: white;
${Link}:hover & {
background-color: greenyellow;
color: black;
}
`;
class Hello extends React.Component{
render() {
return(
<div>
<Link>Hello World</Link>
<Link2>Hello Again</Link2>
</div>
)
}
}
Basically, hovering mouse on my <Link> should trigger a change in background-color in <Link2>.
This is not happening. Any ideas why?
I prepared a code snippet here: https://codesandbox.io/s/qv34lox494

You can refer to styled-components which are children of your styled-component, not side-by-side.
See a quote from the doc:
Here, our Icon component defines its response to its parent Link being
hovered
For your problem, you can create a wrapper for both of your links, and use the adjacent sibling selector in CSS like this:
const Wrapper = styled.div`
& ${Link}:hover + ${Link2} {
background-color: greenyellow;
color: black;
}
`;
https://codesandbox.io/s/mo7kny3lmx

The other way is to modify your selector on Link2 to use siblings (now it's nested item selector). In that case you can get rid of extra wrapper
const Link = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
`;
const Link2 = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: steelblue;
color: white;
${Link}:hover + & {
background-color: greenyellow;
color: black;
}
`;
class Hello extends React.Component{
render() {
return(
<div>
<Link>Hello World</Link>
<Link2>Hello Again</Link2>
</div>
)
}
}

you can do it like this. it works for many components:
const Hi0 = styled.div`
width:75px;
height:75px;
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
border-radius:50%;
`;
const Hi1 = styled.div`
width:75px;
height:75px;
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
border-radius:50%;
`;
const Hi2 = styled.div`
width:75px;
height:75px;
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
border-radius:50%;
`;
const Ind = styled.div`
width:75px;
height:75px;
border-radius:50%;
display: flex;
align-items: center;
padding: 5px 10px;
background: steelblue;
color: white;
transition:0.5s;
`;
const Wrapper = styled.div`
${Hi0}:hover ~ ${Ind} {
background: blue;
};
${Hi1}:hover ~ ${Ind} {
background: red;
};
${Hi2}:hover ~ ${Ind} {
background: yellow;
};
`;
class App extends React.Component{
render() {
return(
<Wrapper>
<Hi0>Hello World</Hi0>
<Hi1>Hello World</Hi1>
<Hi2>Hello World</Hi2>
<Ind>Hello Again</Ind>
</Wrapper>
)
}
}
export default App;
sandboxexemple

Related

why this component height is not full?

This is my cart component code. I am using styled components.
import React from "react";
import styled from "styled-components";
import { useSelector, useDispatch } from "react-redux";
import { remove } from "../../features/cartSlice";
const Cart = () => {
const pizzaProducts = useSelector((state) => state.cart);
const dispatch = useDispatch();
console.log(pizzaProducts);
const handleRemove = (id) => {
dispatch(remove(id));
};
return (
<CartContainer>
<CartHeading>Your cart</CartHeading>
<CartWrapper>
{pizzaProducts.map((pizzaProduct, index) => {
return (
<CartCard key={index}>
<CartImg src={pizzaProduct.img} alt="err" />
<CartInfo>
<CartTitle>{pizzaProduct.name}</CartTitle>
<CartDescription>{pizzaProduct.desc}</CartDescription>
<CartPrice>{pizzaProduct.price}</CartPrice>
<CartButton
id="btn"
onClick={() => handleRemove(pizzaProduct.id)}
>
Remove
</CartButton>
</CartInfo>
</CartCard>
);
})}
</CartWrapper>
</CartContainer>
);
};
const CartContainer = styled.div`
height: 100vh;
width: 100%;
min-width: 100vh;
min-height: 100%;
background: #000;
#media screen and (max-width: 400px) {
width: 100%;
}
`;
const CartHeading = styled.h2`
height: 40px;
padding: 30px 0;
text-align: center;
padding-top: 5rem;
margin-bottom: 2rem;
color: white;
font-size: clamp(2rem, 2.5vw, 3rem);
letter-spacing: 4px;
text-transform: uppercase;
`;
const CartWrapper = styled.div`
display: flex;
flex-wrap: wrap;
padding: 10px 0;
justify-content: center;
`;
const CartCard = styled.div`
margin: 0 3rem;
width: 400px;
min-width: 400px;
line-height: 2;
`;
const CartImg = styled.img`
height: 400px;
min-width: 400px;
box-shadow: 8px 8px #fdc500;
`;
const CartInfo = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 1.5rem 0;
`;
const CartTitle = styled.h2`
font-weight: 400;
font-size: 1.5rem;
color: white;
word-spacing: 1px;
letter-spacing: 3px;
`;
const CartDescription = styled.p`
margin-bottom: 1rem;
color: white;
margin: 20px 0;
font-size: 20px;
text-align: center;
word-spacing: 1px;
letter-spacing: 3px;
`;
const CartPrice = styled.p`
margin-bottom: 1rem;
font-size: 2rem;
color: white;
word-spacing: 1px;
letter-spacing: 3px;
`;
const CartButton = styled.button`
font-size: 1rem;
padding: 1rem 4rem;
border: none;
background: #e31837;
color: #fff;
transition: 0.2 ease-out;
&:hover {
background: #ffc500;
transition: 0.2s ease-out;
cursor: pointer;
color: #000;
}
`;
export default Cart;
I am expecting the full height 100%.

How to stop scaling object when object reach 100% width of display for 150% scale etc

I've created 2 almost similar websites. The first one is in Wordpress Elementor second one is React + styled components. In Wordpress site, I have 4 columns like cards (React project has also 4 columns). When I start scale website (CTRL + Wheel Up) cards (included images) scale till it reach 100% width of screen. Then it stops. I'm using standard 100% windows scale with 24" monitor with 1920*1080 resolution.
Also I have a laptop with small display something like 13" FHD but windows scale is set to 150% and there is the problem for my React app.
I'd like to ask you how how can I easy reach this behavior please?
Address for wordpress site is here: https://www.rpgmma.cz/#zapasnici
Different between React project and Wordpress project
I don't know if it is important for this question but here is my code:
Index.js
<ServicesContainer id="services">
<ServicesH1>Naši Atleti</ServicesH1>
<ServiceMainP>Aktuálně nás na profesionální úrovní representují tito atleti. RPG též representuje mnoho atletů
na
amatérské úrovni.</ServiceMainP>
<CenterWrapper>
<ServicesWrapper>
<ServicesCards>
<NameWrapperH3>
<FirstName>Name</FirstName>
<Nickname>"Nickname"</Nickname>
<LastName>LastName</LastName>
</NameWrapperH3>
<SportWrapper>
<SportName>MMA, Box</SportName>
</SportWrapper>
<SocialWrapper>
<a href="https://www.google.com/">
<FacebookIcon/>
</a>
<a href="https://www.google.com/">
<InstagramIcon/>
</a>
</SocialWrapper>
<ServicesIcon src={Photo1}/>
<ButtonWrapper>
<Button>Zjistit více</Button>
</ButtonWrapper>
</ServicesCards>
<ServicesCards>
<NameWrapperH3>
<FirstName>Name</FirstName>
<Nickname>"Nickname"</Nickname>
<LastName>LastName</LastName>
</NameWrapperH3>
<SportWrapper>
<SportName>MMA, Box</SportName>
</SportWrapper>
<SocialWrapper>
<a href="https://www.google.com/">
<FacebookIcon/>
</a>
<a href="https://www.google.com/">
<InstagramIcon/>
</a>
</SocialWrapper>
<ServicesIcon src={Photo2}/>
<ButtonWrapper>
<Button>Zjistit více</Button>
</ButtonWrapper>
</ServicesCards>
<ServicesCards>
<NameWrapperH3>
<FirstName>Name</FirstName>
<Nickname>"Nickname"</Nickname>
<LastName>LastName</LastName>
</NameWrapperH3>
<SportWrapper>
<SportName>MMA, Box</SportName>
</SportWrapper>
<SocialWrapper>
<a href="https://www.google.com/">
<FacebookIcon/>
</a>
<a href="https://www.google.com/">
<InstagramIcon/>
</a>
</SocialWrapper>
<ServicesIcon src={Photo3}/>
<ButtonWrapper>
<Button>Zjistit více</Button>
</ButtonWrapper>
</ServicesCards>
<ServicesCards>
<NameWrapperH3>
<FirstName>Name</FirstName>
<Nickname>"Nickname"</Nickname>
<LastName>LastName</LastName>
</NameWrapperH3>
<SportWrapper>
<SportName>MMA, Box</SportName>
</SportWrapper>
<SocialWrapper>
<a href="https://www.google.com/">
<FacebookIcon/>
</a>
<a href="https://www.google.com/">
<InstagramIcon/>
</a>
</SocialWrapper>
<ServicesIcon src={Photo4}/>
<ButtonWrapper>
<Button>Zjistit více</Button>
</ButtonWrapper>
</ServicesCards>
</ServicesWrapper>
</CenterWrapper>
</ServicesContainer>
Styled.js
export const ServicesContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
background: #010606;
padding-bottom: 20px;
`
export const CenterWrapper = styled.div`
display: flex;
`
export const ServicesWrapper = styled.div`
display: inline-flex;
flex-wrap: wrap;
margin: auto;
justify-content: center;
grid-gap: 16px;
padding: 0 50px;
`
export const ServicesH1 = styled.h1`
font-size: ${firstHeading};
position: relative;
text-align: center;
color: ${white};
margin-bottom: 64px;
#media screen and (max-width: 480px) {
font-size: 2rem;
}
/*underline*/
&:after {
bottom: 0;
content: "";
display: block;
height: 2px;
position: absolute;
background: ${red};
transition: width 0.3s ease 0s, left 0.3s ease 0s;
width: 90%;
left: 5%;
}
`
export const ServiceMainP = styled.p`
text-align: center;
color: ${white};
margin-bottom: 64px;
`
export const ServicesCards = styled.div`
background: ${black};
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 10px;
padding: 30px;
box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
transition: all 0.2s ease-in-out;
&:hover {
transform: scale(1.02);
transition: all 0.2s ease-in-out;
cursor: pointer;
}
`
export const SportWrapper = styled.div`
width: 100%;
`
export const SportName = styled.h4`
color: ${red};
font-size: ${fourthHeading};
margin-bottom: 10px;
`
export const SocialWrapper = styled.div`
width: 100%;
display: flex;
gap: 10px;
margin-bottom: 10px;
`
export const FacebookIcon = styled(FaFacebookF)`
color: ${white};
font-size: 2.3rem;
background-image: url(https://www.google.com);
&:hover {
color: ${red}
}
`
export const InstagramIcon = styled(FaInstagram)`
color: ${white};
font-size: 2.3rem;
&:hover {
color: ${red}
}
`
export const ServicesIcon = styled.img`
margin-bottom: 10px;
`
export const ServicesH2 = styled.h2`
font-size: ${secondHeading};
margin-bottom: 10px;
`
export const ServicesH3 = styled.h3`
font-size: ${thirdHeading};
color: ${white};
margin-bottom: 10px;
`
export const ServicesH4 = styled.h3`
font-size: ${fourthHeading};
margin-right: auto;
color: ${red};
margin-bottom: 10px;
`
export const ButtonWrapper = styled.div`
display: flex;
justify-content: center;
text-align: center;
margin: 20px 0;
`
export const Button = styled.button`
color: ${white};
transition: 0.25s;
background: ${darkRed};
border: 2px solid ${darkRed};
font: inherit;
line-height: 1;
margin: 0.5em;
padding: .8em 1.5em;
font-size: 1.5rem;
font-weight: 900;
text-transform: uppercase;
&:hover, &:focus {
box-shadow: inset 0 0 0 2em #000;
cursor: pointer;
border-color: ${darkRed};
color: #fff;
}
`
export const NameWrapperH3 = styled.h3`
width: 100%;
`
export const FirstName = styled.span`
display: block;
font-size: ${thirdHeading};
color: ${white};
text-align: left;
`
export const Nickname = styled.span`
display: block;
font-size: ${thirdHeading};
color: ${white};
text-align: center;
`
export const LastName = styled.span`
display: block;
font-size: ${thirdHeading};
color: ${white};
text-align: right;
`

How to split CSS of a single element into multiple functions/variables in styled-components?

I have a component that has a very long list of CSS that handles various items within that element.
export const StyledTable = styled((props) => <Table {...props} />)`
padding: 20px;
background-color: white;
border-radius: 20px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
& tbody .ant-table-column-sort,
& thead th.ant-table-column-sort {
background-color: unset;
}
& .ant-select .ant-select-selector {
border-radius: 10px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
color: lightgray;
height: 50px;
font-size: 20px;
display: flex;
align-items: center;
}
& .ant-pagination {
display: flex;
justify-content: center;
align-items: center;
}
& .ant-pagination .ant-pagination-total-text {
color: rgba(102, 220, 141, 1);
}
// and another 100 rows bellow
`;
Some of the CSS is for the rows of the table, others are for the columns, another CSS is for various controls of the table (and provides only the main Table Component, so go figure).
Is there a way to somehow split that css into multiple functions/variables and then do something like:
export const StyledTable = styled((props) => <Table {...props} />)`
padding: 20px;
${rowsCss}
${columnsCss}
${controlsCss}
`
And if that is possible, how do I define rowsCss (and the rest)?
You can just use css blocks:
import { css } from 'styled-components';
const paginationCss = css`
& .ant-pagination {
display: flex;
justify-content: center;
align-items: center;
}
`
export const StyledTable = styled((props) => <Table {...props} />)`
padding: 20px;
${paginationCss}
`

How to center buttons with styled-components?

Can't figure out how to center 2 buttons horizontally with styled-components.
Below is my code.
Tried many ways to center, but didn't work.
import React from "react"
import styled from "styled-components"
const HomeStyles = styled.div`
h1 {
font-size: 1.5em;
text-align: center;
color: royalblue;
}
button {
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid royalblue;
border-radius: 3px;
color: royalblue;
}
`
export default function Home() {
return (
<HomeStyles>
<h1>Title</h1>
<button>Button1</button>
<button>Button2</button>
</HomeStyles>
)
}
UPDATE: I need to center buttons horizontally
Have you tried using flexbox on parent element?
const HomeStyles = styled.div`
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
....
`;
const ButtonsWrapper = styled.div`
display: flex;
justify-items: center;
align-items: center;
`;
<HomeStyles>
<h1>Title</h1>
<ButtonsWrapper>
<button>Button1</button>
<button>Button2</button>
</ButtonsWrapper>
</HomeStyles>

target child element styled components

I'm trying to change the nth-child(2) background color of the ColorBox element by targeting it as a child of ImgGrid but I just can't seem to get it to work, I have tried multiple variations with different elements and nothing seems to be working
This will change the background color if I don't try to target an nth-child element
const ImgGrid = styled.div`
display: flex;
flex-wrap: wrap;
flex-direction: row;
${ColorBox} {
background: #ff00ff;
}
`
How can I target the nth-child(2) of the ColorBox element?
import React from 'react'
import styled from 'styled-components'
// import Img from '../../atoms/Img'
import { array, bool } from 'prop-types'
const Wrap = styled.div`
padding: 20px 0;
`
const BoxWrap = styled.div`
position: relative;
border: 1px solid #000;
height: auto;
padding: 20px;
`
const Title = styled.div`
position: absolute;
display: flex;
align-items: center;
top: -20px;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
height: 40px;
background: #f6f6f6;
padding: 10px;
`
const BoxInner = styled.div`
width: 100%;
height: 100%;
`
const ColorBox = styled.div`
height: 60px;
width: 100%;
background: #FFD700;
`
const ImgCell = styled.div`
flex: 0 0 25%;
padding: 5px;
`
const ImgGrid = styled.div`
display: flex;
flex-wrap: wrap;
flex-direction: row;
&:nth-child(2) ${ColorBox} {
background: #ff00ff;
}
`
const ImgCellInner = styled.div`
position: relative;
`
// const ImgText = styled.div`
// position: absolute;
// bottom: 0;
// left: 0;
// padding: 5px;
// width: 100%;
// background: rgba(0,0,0,0.7);
// color: #fff;
// `
const ImgWrap = styled.div`
width: 100%;
`
const ColorWrap = styled.div`
`
const Filter = ({ filterData, color }) => (
<Wrap>
<BoxWrap>
<Title>
For Women
</Title>
<BoxInner>
<ImgGrid>
{filterData.map(filter =>
<ImgCell>
<ImgCellInner>
<ImgWrap>
{color &&
<ColorWrap>
<ColorBox />
{filter.text}
</ColorWrap>
}
</ImgWrap>
</ImgCellInner>
</ImgCell>,
)}
</ImgGrid>
</BoxInner>
</BoxWrap>
</Wrap>
)
/* eslint-disable*/
Filter.propTypes = {
filterData: array,
color: bool,
}
Filter.defaultProps = {
filterData: array,
color: bool,
}
export default Filter
I can assume your code is not working because &:nth-child(2) means you are selecting ImgGrid which is second child itself. Try to specify ImgCell as nth-child(2):
const ImgGrid = styled.div`
display: flex;
flex-wrap: wrap;
flex-direction: row;
${ImgCell}:nth-child(2) ${ColorBox} {
background: #ff00ff;
}
`
I'm not sure about scoping, so probably you need to use & before:
const ImgGrid = styled.div`
display: flex;
flex-wrap: wrap;
flex-direction: row;
& ${ImgCell}:nth-child(2) ${ColorBox} {
background: #ff00ff;
}
`
If you stumble on this question looking for how to target all children elements, here is how;
const ParentDiv = styled.div`
>* {
background: white;
padding: 5px;
};
/* ...etc */
`;
I had the same problem. :focus-within in parent element worked for me, could solve your problem too.
Eg:
export const Parent = styled.div`
display: flex;
align-items: center;
border: 1px solid #000;
&:focus-within {
border: 1px solid #2ADCC6;
}
`;
export const Child = styled.input`
flex: 1;
border: none;
`;
Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within

Resources