Styled Components with React, driving colours using state - reactjs

I am using a clicked state for 3 components, when each component is clicked, it will set the state to e.g 1,2,3.
This is pretty basic but it looks like this.
const [selectedTemplate, setSelectedTemplate] = useState(0)
<TemplateContainer>
<DummyTemplateImage
onClick={() => {
setSelectedTemplate(1);
}}
>
<ImageContainer src={General}/>
</DummyTemplateImage>
<Typography variant="h5" fontSize="18px" color="primary">
Text!!
</Typography>
<Typography variant="subtitle4" color="black">
Text!
</Typography>
</TemplateContainer>
Pretty simple. However, when the box is selected, e.g you select option 1, i'd like it to change the background to be green.
This is my styled-component.
const TemplateContainer = styled.div`
width: 35%;
height: 100%;
border-radius: 0.5em;
justify-content: center;
align-items: center;
display: flex;
flex-direction: column;
text-align: center;
`;
How would I drive this?

Related

Styled Components Injects wrong classes on wrong elements

I'm witnessing a weird behavior when in styled-components with SSR in remix.run
I have a ProductCard Component that renders a normal product card with styled-components
ProductCard.tsx
import Button from "../Button";
function ProductCard({ product }: props) {
return (
<>
<Wrapper>
....
<ButtonsWrapper>
<Cart
onClick={addToCart}
mode={addedToCart ? "secondary" : "primary"}
disabled={loading}
key="cart-button"
>
{addedToCart ? "Added!" : "Add to cart"}
{loading && <LoadingSpinner src="/images/responses/loader.svg" />}
</Cart>
<ShareButton mode="secondary" aria-label="share">
<Icon id="share" />
</ShareButton>
</ButtonsWrapper>
</Wrapper>
</>
);
}
const Cart = styled(Button)`
flex: 1.1;
display: flex;
justify-content: center;
gap: 10px;
`;
const ShareButton = styled(Button)`
padding: 0.9rem;
`;
const Wrapper = styled.div`
--border-radius: ${clamp(15, 20)};
--columnGap: ${clamp(20, 30)};
display: flex;
flex-direction: column;
gap: var(--columnGap);
justify-content: space-between;
width: 100%;
height: 100%;
margin: auto;
background-color: var(--azure-15);
padding: 1.9rem 1.5rem;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow-lg);
border: var(--border-lg);
`;
const ButtonsWrapper = styled.div`
display: flex;
justify-content: space-between;
gap: 0.625rem;
`;
export default ProductCard;
Button.tsx
const Button = styled.button<{ mode: "primary" | "secondary" | "dark" }>`
display: grid;
/* justify-content: center; */
align-items: center;
text-align: center;
color: var(--mintCream);
padding: ${clamp(9, 10)} ${clamp(20, 30)}; // this clamp function just generates the css clamp func with calculating the values with some equations
box-shadow: var(--box-shadow-md);
border: var(--border-md);
border-radius: 12px;
text-decoration: none;
cursor: pointer;
transition: all 500ms ease;
font-size: ${clamp(13, 16)};
&:disabled {
cursor: not-allowed;
opacity: 0.7;
}
#media (hover: hover) and (pointer: fine) {
&:hover:enabled {
transform: translateY(-2px); }
}
width: fit-content;
`;
The normal render of this Component is as follows
But when navigating to another path and returning to it on / , it renders like this
This problem only happens in production and works fine on local server...
when inspecting elements, I find that the class name of the Cart Component is also injected into the ShareButton Element
I can't find an explanation for this problem and it gets weirder... When I swap the order of the variables Cart and ShareButton or swap them with the Wrapper Element, some other weird behaviors happen like the one below
In this case, the class name of the Cart Component got injected on the parent elemnt of the parent element of the ProductCard Component
I've probably hit on 4 of these rendering issues but all of them share the same problem, the class name of the Cart Components gets injected on a wrong dom element, whether it's a parent or a sibiling
You can view the first weird behaviour here https://store.ieeenu.com
You will find the product component on the root path, navigate to some path like categories/circuits-1-ecen101 and return to the root and you will see the issue
also, you can review the second weird behavior in a previous build here
https://ieee-nu-store-r243eocii-omarkhled.vercel.app/
I just changed the initialization order of the Cart and ShareButton Components as I said earlier
I don't know whether this problem is from styled-components or from remix (this is the first time for me using remix), it's mentioned here https://github.com/remix-run/remix/issues/1032 that the lack of the babel-plugin-styled-components in remix.run introduces some problems in rehydration but I'm not sure that this is the issue I'm facing...
Thanks for reading this till the end and excuse my English, I'm not a native speaker :"

Question related to how to center align via flex attribute

I want to make a page like this picture. To do this, I want to center the part drawn in blue, but my code doesn't work properly. What's wrong? Any advice would be appreciated.
import {
Col, Row,
} from 'react-bootstrap';
const content=css`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const imageContianer=css`
width: 100%;
height: 60%;
`;
const About =()=>{
return (
<div css={content}>
<p>Who am I ?</p>
<div css={imageContianer}>
<Row>
<Col>
<img
src={ Icon }
width='200'
height='180'
alt='Icon' />
</Col>
<Col>
<p>First</p>
<p>Second</p>
<p>Third</p>
</Col>
</Row>
</div>
</div>
);
}
This is the result. The "Who am i" part even appears in the container above. What's the problem?
import {
Col, Row,
} from 'react-bootstrap';
const content=css`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const imageContianer=css`
width: 100%;
height: 60%;
display: flex;
align-items: center;
justify-content: center;
`;
const rowContainer=css`
flex: 0 0 60% !important;
align-items: center;
justify-content: center;
`;
const About =()=>{
return (
<div css={content}>
<p>Who am I ?</p>
<div css={imageContianer}>
<Row css={rowContainer}>
<Col>
<img
src={ Icon }
width='200'
height='180'
alt='Icon' />
</Col>
<Col>
<p>First</p>
<p>Second</p>
<p>Third</p>
</Col>
</Row>
</div>
</div>
);
}
Hopfully code above can solve your problem. basicly you need to know how flex work, it's just like how grid on bootstrap css framwork does.
note: i haven't use styled-components like you do using css but i just follow your code example.
Playground
Leave a comment if my answer didn't working out the way want

How to refactor code using styled components in react and typescript?

i want to refactor code for the styled components using react and typescript.
i have two link black and blue sharing same css and some style differ.
below is the code,
return (
<Wrapper>
<ButtonLink a="someurl">
black
</ButtonLink>
<ButtonLink a="url">
blue
</ButtonLink>
</Wrapper>
);
const ButtonLink = styled.a`
border: none;
background: none;
display: flex;
justify-content: center;
align-items: center;
`;
Now for the black link i want to add background-color: black and for blue link i want to add the background-color blue.
how can i add these styles to those two links using styled components. could someone help me with this. thanks.
You need to pass properties as a props to your components, for example
<ButtonLink color="red" href="#">Red</ButtonLink>
const ButtonLink = styled.a`
...,
color: ${props => props.color}
`
You could use props in your styled component
const ButtonLink = styled.a`
border: none;
background: ${props => props.bgColor};
display: flex;
justify-content: center;
align-items: center;`
Then pass in the props like this
return (
<Wrapper>
<ButtonLink a="someurl" bgColor="black">
black
</ButtonLink>
<ButtonLink a="url" bgColor="blue">
blue
</ButtonLink>
</Wrapper>
);
Alternatively if you don't want to pass in props you could extend the initial ButtonLink component
const ButtonLink = styled.a`
border: none;
display: flex;
justify-content: center;
align-items: center;`
const BlueButtonLink = styled(ButtonLink)`
background-color: #0000FF;`
const BlackButtonLink = styled(ButtonLink)`
background-color: #000;`
return (
<Wrapper>
<BlackButtonLink a="someurl">
black
</BlackButtonLink>
<BlueButtonLink a="url" >
blue
</BlueButtonLink>
</Wrapper>
);
Just add add the color as a props of your ButtonLink component. But don't forget to add the interface for it since you are using TypeScript:
return (
<Wrapper>
<ButtonLink color="black" a="someurl">
black
</ButtonLink>
<ButtonLink color="blue" a="url">
blue
</ButtonLink>
</Wrapper>
);
interface ButtonLinkProps {
color: string
}
const ButtonLink = styled.a<ButtonLinkProps>`
color: ${props => props.color}
border: none;
background: none;
display: flex;
justify-content: center;
align-items: center;
`;

Centering icon and text

Im having a hard time centering a text with awesome font icon, and also centering the icons themselves.
Im using styled components like so:
const StyledIcon = styled(FontAwesomeIcon)`
width: 50px;
display: flex;
justify-content: center;
font-size: 30px;
margin-left: 50px;
`;
const Text = styled.div`
font-size: 13px;
display: flex;
justify-content: center;
`;
and in my component I have the following
<StyledIcon icon={icon1} />
<Text>Charts + Graphs</Text>
<StyledIcon icon={icon2} />
<Text>Classes</Text>
<StyledIcon icon={icon3} />
<Text>Student Information</Text>
<StyledIcon icon={icon4} />
<Text>Knowledge Database</Text>
<StyledIcon icon={icon5}/>
<Text>Class Notes</Text>
This is how it currently looks, any suggestions on how to center text & icon so that they appear in the center of the shaded box?
Use flexbox.
const WrapperAroundIconsAndText = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`;

Vertical align and centre multiple divs using Flexbox

I am trying to vertically align two set of rows, each of which contains an image on one side, and text on the other side. Although I have experience with using flex to align vertically by using the code below, seems like in this particular situation I have to use something different:
justify-content: center;
flex-direction: column;
text-align: center;
This is what I am trying to achieve (Note that the red box is the image while the gray box is the text):
However, I am getting the situation below, with the text not vertically centered but top aligned with the image:
This is how the DOM structure looks like (ReactJS):
<LandingPinkDiv>
<Grid container spacing={24}>
<Grid item xs={12}>
<LandingTitleWhite>Title</LandingTitleWhite>
</Grid>
<LandingRowDiv>
<Grid item xs={6}>
<LandingImageDiv>
<LandingImage
src={1}
width="320px"
height="304px"
/>
</LandingImageDiv>
</Grid>
<Grid item xs={6}>
<LandingTextContainer>
<LandingSubheadingWhite>
Subheading
</LandingSubheadingWhite>
<LandingSubtitleBlack>
SubTitle
</LandingSubtitleBlack>
</LandingTextContainer>
</Grid>
</LandingRowDiv>
<LandingRowDiv>
<Grid item xs={6}>
<LandingTextContainer>
<LandingSubheadingWhite>
SubHeading
</LandingSubheadingWhite>
<LandingSubtitleBlack>
Subtitle
</LandingSubtitleBlack>
</LandingTextContainer>
</Grid>
<Grid item xs={6}>
<LandingImageDiv>
<LandingImage
src={2}
width="320px"
height="197px"
/>
</LandingImageDiv>
</Grid>
</LandingRowDiv>
</Grid>
</LandingPinkDiv>
The CSS counterpart is like this:
export const LandingRowDiv = styled.div`
display: flex;
/* justify-content: center;
flex-direction: column;
text-align: center; */
margin-bottom: 10%;
padding-left: 10%;
padding-right: 10%;
`;
export const LandingPinkDiv = styled.div`
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
height: 170vh;
background: #e72564 !important;
`;
export const LandingTextContainer = styled.div`
display: flex;
justify-content: center;
flex-direction: column;
text-align: center;
margin-right: 10%;
`;
You need to add align-items: center to your LandingRowDiv styled component:
export const LandingRowDiv = styled.div`
align-items: center;
display: flex;
justify-content: center;
flex-direction: row;
text-align: center
margin-bottom: 10%;
padding-left: 10%;
padding-right: 10%;
`;
You should use align-items: center; in 'LandingRowDiv' styled-component.
Not sure I get it right but you could consider the following html
<figure>
<img src="" alt="">
<figcaption>
<p>Text</p>
</figcaption>
</figure>
And then the following css
figure {
display: flex;
width: 100%;
}
figure img {
width: 50%;
}
figure figcaption {
display: flex;
justify-content: center;
align-items: center;
width: 50%;
}
(you can use align-self on p instead of align-items)

Resources