React Styled Component's CSS method optimization - css

Which is more optimized and why?
I hear that the css method from Styled-component is pretty expensive but I'm wondering if the multiple nested ${(prop) => {}} is more expensive than the single fn with the css method used inside.
Approach 1
const Foo = styled.div`
border-radius: 50%;
display: flex;
width: ${(props) => props.size};
height: ${(props) => props.size};
color: ${(props) => props.bgColor};
background-color: ${(props) => props.bgColor};
`;
vs
Approach 2
const Bar = styled.div`
border-radius: 50%;
display: flex;
${(props) => {
return css`
width: ${props.size};
height: ${props.size};
color: ${props.bgColor};
background-color: ${props.bgColor};
`;
}}
`;

Performance difference should be negligible. The only optimization Styled Components would make is if your styles were static (with no interpolations).
Note that styled.div or any other of the Styled CSS methods already do the same work as css. And these methods accept functions as arguments (instead of interpolated strings). So you can take it a step further and do this:
const Baz = styled.div((props) => css`
border-radius: 50%;
display: flex;
width: ${props.size};
height: ${props.size};
color: ${props.bgColor};
background-color: ${props.bgColor};
`);

Related

Is there any way i can style an element based on other elements state using styled components?

I just started using styled-components and currently converting all my css into styled components in a project. But i am not sure how to achive some things and i could not find anything relevant in documentation too. I would like to know if the following problem is achievable using this approach in styled-components.
I have two checkboxes(radio input), if its checked i want to style a span element(Dot component in this case).
<div className="acc__type">
<RadioInput type="radio" name="accType" id="dot-1" required />
<RadioInput type="radio" name="accType" id="dot-2" required />
<Category>
<AccTypeLabel for="dot-1">
<Dot></Dot>
<AccTypeTitle>Student</AccTypeTitle>
</AccTypeLabel>
<AccTypeLabel for="dot-2">
<Dot></Dot>
<AccTypeTitle>Staff</AccTypeTitle>
</AccTypeLabel>
</Category>
</div>
here are my styled components
export const RadioInput = styled.input`
display: none;
`;
export const Category = styled.div`
display: flex;
width: 80%;
margin: 15px 0;
justify-content: space-between;
`;
export const AccTypeLabel = styled.label`
display: flex;
align-items: center;
`;
export const AccTypeTitle = styled.div`
font-size: 20px;
font-weight: 500;
`;
export const Dot = styled.span`
height: 18px;
width: 18px;
background: #d9d9d9;
border-radius: 50%;
margin: 10px;
border: 5px solid transparent;
transition: all 0.3s ease;
//here iam trying to change this components styles based on <RadioInput/> components state.
#dot-1:checked & {
border-color: #d9d9d9;
background: #9b59b6;
}
`;
in css i did this and it worked
#dot-1:checked ~ span,
#dot-2:checked ~ span {
border-color: var(--sub-grey);
background: var(--main-purple);
}
/* <Dot/> component was span here */
any help!
In Styled Components it's an ever so slightly different syntax, the reason is that it hashes the class names in a way that makes it difficult to target them. So this is how you do it in a way that ensures SC knows what's what:
const dot1StyledComponent = styled.div`
...
`;
${ dot1StyledComponent }:checked ~ span {
border-color: #d9d9d9;
background: #9b59b6;
}

Styled compoenents/emotion: add a style object to apply to different components

I create different icons in Emotion (could be Styled Components as well), and I apply the exact styling to each icon:
const BellIcon = styled(Bell)`
width: ${(props) => props.theme.sizes.iconDimension};
height: ${(props) => props.theme.sizes.iconDimension};
flex-shrink: 0;
`;
const PlayIcon = styled(Play)`
width: ${(props) => props.theme.sizes.iconDimension};
height: ${(props) => props.theme.sizes.iconDimension};
flex-shrink: 0;
`;
const RefreshIcon = styled(Refresh)`
width: ${(props) => props.theme.sizes.iconDimension};
height: ${(props) => props.theme.sizes.iconDimension};
flex-shrink: 0;
`;
Is there a way to to outsource the styling into an object and apply the same styles to each icon using the object? (or another method? Just so the code isn't repetitive)
You can utilize the "css" function from "styled-components" to group styles in an object.
Like this:
import { css } from 'styled-components';
const GroupedStyles = css`
width: ${(props) => props.theme.sizes.iconDimension};
height: ${(props) => props.theme.sizes.iconDimension};
flex-shrink: 0;
`;
const RefreshIcon = styled(Refresh)`
${GroupedStyles};
`;
const PlayIcon = styled(Play)`
${GroupedStyles};
`;
Assuming that your icon components are SVGs, I'd do the following:
const IconWrapper = styled.div`
svg {
width: ${(props) => props.theme.sizes.iconDimension};
height: ${(props) => props.theme.sizes.iconDimension};
flex-shrink: 0;
}
`;
And then use it as:
<IconWrapper>
<Icon />
</IconWrapper>

update properties of style component using switch statement

I know there's a similar question but what I need is different.
I have declared the common styles that my button will be using and I'm using a function with a switch statement that has different properies for different buttons that I will be using in other pages and for one case I need the border-radius and padding different from the common one, how can I update(or replace) the value without using !important or && {.
Here's the code
import { TTheme } from 'src/styles/Themes/Theme';
import styled, { css, FlattenSimpleInterpolation } from 'styled-components';
const getVariantCSS = <T extends TTheme>(props: T): FlattenSimpleInterpolation => {
const { theme } = props;
switch (props.variant) {
case 'secondary':
return css`
background-color: ${theme.colors.white};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
}
`;
case 'half':
return css`
color: ${theme.colors.white};
background-color: ${theme.colors.primary};
&& {
border-radius: ${theme.radius.half};
padding: ${theme.paddings.small};
}
border: ${theme.borders.solid2} ${theme.colors.white};
`;
case 'dark':
return css`
background-color: ${theme.colors.tertiary};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverDark};
box-shadow: ${theme.boxShadows.primary};
filter: ${theme.filter.brightness};
border: ${theme.borders.none};
opacity: ${theme.opacity.default};
}
`;
default:
return css`
background-color: ${theme.colors.primary};
color: ${theme.colors.white};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
}
`;
}
};
export const StyledButton = styled.button`
${getVariantCSS}
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
I suggest using the cascade. just place "getVariantsCSS" below the main styles and then the desired styles will be applied and then "important" and "&&" is not needed.
https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance#the_cascade
export const StyledButton = styled.button`
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
${getVariantCSS}
`

How to add a css property only when condition true using styled components and react?

i wanted to add border property only when isOpen condition true using styled components and react.
below is my code,
const Wrapper = styled.div<{ $isOpen: boolean }>`
border: 1px solid black;
display: flex;
`;
How to apply border only when isOpen is true?
could someone help me with this. thanks.
You can try like this:
const Wrapper = styled.div`
display: flex;
${({isOpen}) =>
isOpen &&
css`
{
border: 1px solid black;
}`
}
`;
Grabbing an example from the home page of styled-components:
import styled, { css } from 'styled-components'
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
${props =>
props.primary &&
css`
background: palevioletred;
color: white;
`};
`
How you would use it in the react renderer:
render(
<Container>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
</Container>
);

How to add media query to non component variable in styled components?

I am working on a React JS project where I am using styled-components for styling the web pages.
I am using reactstrap components in the project.
I am styling the Button component of reactstrap and trying to add the media query.
ButtonX Component
import styled, {css} from 'styled-components';
import { Button } from 'reactstrap';
import media from '../media';
const orange = `
background-color: #E4572E;
border: 1px solid #E4572E;
color: #fff;
&:hover,
&:focus {
background-color: #e97857;
border: 1px solid #e97857;
color: #fff;
}
`;
const inline = `
position: absolute;
top: 1rem;
right: 1rem;
`;
const ButtonX = styled(Button)`
padding: 0.5rem 1.5rem;
font-weight: 500;
font-size: 0.8rem;
transition: all 0.4s linear;
border-radius: 0.2rem;
${props => props.orange ? css`${orange}` : ''};
${props => props.inline ? css`${inline}`: ''}
${props => props.inline ?
(media.smalldevice`
top: 4rem;
right: 5rem;
`)
: ''}
`;
export {
ButtonX
}
I am Writing the ButtonX component like this
<ButtonX orange="true" inline="true">Sign Up</ButtonX>
As, In the ButtonX component I am checking if inline is set then add the css code as well as media query for the css.
${props => props.inline ? css`${inline}`: ''}
${props => props.inline ?
(media.smalldevice`
top: 4rem;
right: 5rem;
`)
: ''}
I am checking the condition 2 times if inline is true then add css and media query.
1) The above is working, but I want to add both the queries in a single condition which is not working.
2) Else, I would like to know how can I write this media query in the inline variable above like this.
const inline = `
position: absolute;
top: 1rem;
right: 1rem;
${
media.smalldevice`
top: 4rem;
right: 5rem;
`
}
`;
I tried the second one but that is not working as I am sure if we can write media query in the variable.
When adding something like a media query inside a template string, you are interpolating a function. These cannot work inside normal template literals as you have provided inline with.
styled-components provides a helper called css that can be used to interpolate functions. In your case it can be used:
import { css } from "styled-components";
const inline = css`
position: absolute;
top: 1rem;
right: 1rem;
${media.smalldevice`
top: 4rem;
right: 5rem;
`}
`;

Resources