target child element styled components - reactjs

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

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%.

react transition effect not work after async thunk

Although I have updated the todo status, the checkbox effect is not working correctly, as if no effect has been applied, what could be the reason for this? I don't think there is a problem with the api file, but the api request is taking a long time.I think it's because css doesn't render again, I can't think of anything else..
Thank you for helping
import React from "react";
import { useDispatch } from "react-redux";
import { toggleTodos } from "../redux/slice/thunkActions";
import styled from "styled-components";
const Content = styled.div`
color: #fff;
text-transform: capitalize;
`;
const Options = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
`;
const EditButton = styled.button`
cursor: pointer;
background-color: #ff6b81;
padding: 0.7rem 2rem;
color: #fff;
border-radius: 0.5rem;
font-weight: bold;
`;
const InputWrapper = styled.label`
position: relative;
`;
const Input = styled.input`
position: absolute;
left: -99999px;
top: -99999px;
&:checked + span {
background-color: #1890ff;
transition: 1s;
&:before {
left: calc(100% - 0.2rem);
transform: translateX(-100%);
}
}
`;
const Slider = styled.span`
display: flex;
width: 5rem;
height: 2.5rem;
cursor: pointer;
border-radius: 10rem;
background-color: #fcebb6;
transition: background-color 0.4s;
&:before {
content: "";
position: absolute;
top: 0.2rem;
left: 0.2rem;
width: 2.1rem;
height: 2.1rem;
border-radius: 2.1rem;
transition: 1s;
background-color: #fff;
}
`;
const Todo = ({ todo }) => {
const dispatch = useDispatch();
const handleChange = (todo) => {
dispatch(toggleTodos(todo));
};
return (
<li>
<Content>{todo.content}</Content>
<Options>
<EditButton type="button">Edit</EditButton>
<InputWrapper htmlFor={`todoContent${todo.id}`}>
<Input
id={`todoContent${todo.id}`}
type={"checkbox"}
onChange={() => handleChange(todo)}
checked={todo && todo.isCompleted}
/>
<Slider />
</InputWrapper>
</Options>
</li>
);
};
export default Todo;

Range Slider with React and Typescript

I have created range slider but when we change the min value then it will not work. I want dynamic range Slider with ticks and moving label with respect to thumb without using any package.
This is my code below. i am expecting to create a dynamic range slider without using any package and also slider have ticks and movable thumbs which shows value with respect to thumbs
import { useCallback } from 'react';
import { Styles } from './range-slider-style';
interface IVersionSliderProps {
latestVersion: number;
olderVersion: number;
onChange: (val: any) => void;
}
export function VersionSlider(props: IVersionSliderProps) {
const setValue = useCallback((e) => {
console.log(e.target.value);
const newVal = e.target.value;
const negNewVal = -10 * Number(newVal);
console.log(negNewVal);
(document.querySelector('.range-text') as HTMLDivElement).style.left = (newVal + '%'); //Set range left position
(document.querySelector('.range-text') as HTMLDivElement).style.transform = 'translate(' + negNewVal + '%, 20px)'; //Set range translate to correct
(document.querySelector('.range-text') as HTMLDivElement).innerHTML = newVal; //Set range text equal to input position
}, []);
return (
<Styles>
<div className="input-container">
<input
id='#input'
type="range"
min={olderVersion}
max={latestVersion}
//value="1"
onChange={setValue}
step='.01' />
<div className="range-text">0</div>
</div>
</Styles>
);
}
//Css part below:
import styled from 'styled-components';
export const Styles = styled.div`
align-items: center;
display: "flex";
height: 100px;
color: #888;
margin-top: 2rem;
flex-direction:column;
margin-bottom: 2rem;
width: 1200px;
.value {
font-size: 1rem;
}
.input-container {
position: relative;
height:10px;
display: flex;
background: border-box;
width: 100%;
padding: 0;
}
.marking {
height:20xp;
widht:100%;
background-color: "black";
margin-top: 20px;
}
input[type="range"] {
appearance: none;
background-color: #56B0C9;
width: 100%;
height: 8px;
padding: 0;
}
input[type="range"]::-webkit-slider-thumb {
-moz-appearance: none !important;
appearance: none !important;
position: relative;
height: 20px;
width: 100px;
background: transparent;
cursor: ew-resize;
z-index: 2;
}
input[type="range"]::-moz-range-thumb {
-moz-appearance: none !important;
appearance: none !important;
position: relative;
height: 20px;
width: 100px;
background: transparent;
cursor: pointer;
z-index: 2;
}
.range-text {
position: absolute;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
background: white;
text-align: center;
line-height: 1;
height: 18px;
width: 60px;
transform: translate(0, 2px);
}`;

Target another styled component on hover not working

I need help with hover in styled components. If hover is in component and affect that component, that work. But if hover is in component and affect another component, not working.
DropDownContent not show on DropDownLi:hover.
export const DropDownLi = styled(StyledLi)`
display: inline-block;
&:hover {
color: red;
}
`;
export const DropDownContent = styled.div`
display: none;
position: absolute;
min-width: 160px;
z-index: 1;
${DropDownLi}:hover & {
display: block;
}
/* not show on hover */
`;
Not working in next example.
export const DropDownLi = styled(StyledLi)`
display: inline-block;
&:hover ${DropDownContent} {
color: red;
}
`;
<StyledUl>
<DropDownLi>$ Currency</DropDownLi>
<DropDownContent>dvsdv</DropDownContent>
<DropDownLi>English</DropDownLi>
<StyledLi>Login</StyledLi>
</StyledUl>
Try to remove &:
export const DropDownContent = styled.div`
display: none;
position: absolute;
min-width: 160px;
z-index: 1;
${DropDownLi}:hover {
display: block;
}
/* not show on hover */
`;
I found a solution for this problem. The code that works is below.
<StyledUl>
<DropDownLi>
$ Currency
<DropDownContent>dvsdv</DropDownContent>
</DropDownLi>
</StyledUl>
export const StyledLi = styled.li`
float: left;
cursor: pointer;
`;
export const DropDownContent = styled.div`
display: none;
position: absolute;
min-width: 160px;
z-index: 1;
`;
export const DropDownLi = styled(StyledLi)`
display: inline-block;
`;
export const StyledUl = styled.ul`
list-style-type: none;
margin: 0;
overflow: hidden;
color: black;
${DropDownLi}:hover > ${DropDownContent} {
display: block;
}
`;

React styled-components: refer to other components

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

Resources