Use props to switch width using styled components mixins - css

Tech used - Styled components and react
I have a mixin to make my app responsive
import { css } from 'styled-components';
export default {
smallScreen: (...args: any) => css`
#media (max-width: 600px) {
${css(...args)}
}
`,
}
In another react component, I want to use the above defined method to write css that applied on small screens.
const SideNavWrapper = styled.article`
background: red; // this works
width: ${props => props.expanded ? '260px' : '80px'}; // this works
${media.smallScreen({
background: 'yellow', // this works
width: `${props => props.expanded ? '100%' : '20px'}`, // this doesn't work. props is undefined.
})}
`;
Depending on props.expanded, I want to switch the width of SideNavWrapper. However it doesn't work on smaller screens.
Background color changes as expected but not the width. On debugging, I realized that props is undefined. Any ideas what am I missing? Thank you so much!

Another way which you could use and in my opinion would be much cleaner to read and thus maintainable is the following:
const getCorrectWidth = ({ expanded }) => (
expanded
? 260
: 80
);
const getCorrectSmallWidth = ({ expanded }) => (
expanded
? '100%'
: '20px'
);
const SideNavWrapper = styled.article`
background: red;
width: ${getCorrectWidth}px;
${media.smallScreen`
background: yellow;
width: ${getCorrectSmallWidth}
`}
`;
The above has clear functions which tell the developer what they are doing. Syntax looks clean, also.

Would you try:
${props => {
return (media.smallScreen({
background: 'yellow',
width: `${props.expanded ? '100%' : '20px'}`,
}))
}}

Related

Understanding css helper function in styled components

Styled components has a helper css function. But I don't understand when should I used it.
For example this is their example where they use it:
import styled, { css } from 'styled-components'
const complexMixin = css`
color: ${props => (props.whiteColor ? 'white' : 'black')};
`
const StyledComp = styled.div`
/* This is an example of a nested interpolation */
${props => (props.complex ? complexMixin : 'color: blue;')};
`
But if we take similar example from docs here they don't use it:
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
Their description is also not clear and is confusing me:
A helper function to generate CSS from a template literal with
interpolations. You need to use this if you return a template literal
with functions inside an interpolation due to how tagged template
literals work in JavaScript.
Can someone help explain why we need it?
PS this answer also doesn't use it
I use the css function when I create variants for a component:
that is variant switcher:
const sizeVariant: Record<NonNullable<StyledLogoProps['size']>, ReturnType<typeof css>> = {
small: css`
width: 44px;
height: 44px;
`,
regular: css`
width: 93px;
height: 93px;
`,
};
that is component was created by 'styled-components':
interface StyledLogoProps {
size: 'small' | 'regular';
}
export const StyledLogo = styled.div<StyledLogoProps>`
${({ size }) => sizeVariant[size]}
`;
and this is the use in the react:
<>
<StyledLogo size="regular" />
<StyledLogo size="small" />
</>
quite a useful thing

How to conditionally render using object properties in styled-components?

I am trying to conditonally render in styled-components. This code seems to work in this case.
background-color: ${props => (props.active ? 'Black' : 'Green')};
I want to rather use object properties from a JSON file and provide 2 colours to the above condition. Something similar to these below instead of Black and Green.
${colors['Brand/PrimaryBlack']}
${colors['Brand/PrimaryGreen']}
colored.json
{
"colors": {
"Brand/PrimaryBlack": "#424449",
"Brand/PrimaryGreen": "#8ED6C9",
}
}
styles.js
import styled from 'styled-components'
import { colors } from './colored.json'
const Tabs = styled.button`
background-color: ${props => (props.active ? 'Black' : 'Green')};
`
How can I achieve this?
The ternary works exactly the same as your previous code, but just references the keys in your colors JSON, i.e. background-color: ${props => colors[props.active ? "Brand/PrimaryBlack" : "Brand/PrimaryGreen"]};.
{
"colors": {
"Brand/PrimaryBlack": "#424449",
"Brand/PrimaryGreen": "#8ED6C9",
}
}
import styled from 'styled-components'
import { colors } from './colored.json'
const Tabs = styled.button`
background-color: ${props => colors[props.active ? "Brand/PrimaryBlack" : "Brand/PrimaryGreen"]};
`;
You can do what you desire using styled components in the following way:
background-color: ${(props) =>
props.active ? colors["Brand/PrimaryGreen"] : colors["Brand/PrimaryBlack"]};
Find the working CodeSandBox here
Inside of Template literal you pass any valid JavaScript code inside of ${} expression even call to function so if you have an object which you want to access some keys you can just access those keys as you would do in a normal JavaScript code. so if you have an object colors with some properties you can access it inside of you Styled Component like this
const colors = {
"Brand/PrimaryGreen": "green",
"Brand/PrimaryBlack": "black"
};
const Comp = styled.div`
background: ${props => props.active? colors["Brand/PrimaryBlack"] : colors["Brand/PrimaryGreen"]};
color: #fff;
`;
You can simply do this
<TagName active={this.state.active}>Test</TagName>
And in your styles something like this:
const TagName = styled.button`
width: 100%;
outline: 0;
border: 0;
height: 100%;
justify-content: center;
align-items: center;
line-height: 0.2;
${({ active }) => active && `
background: blue;
`}
`;

Increase size of Twemoji in REACT

My REACT component's code is like this
import React from 'react';
import { Twemoji } from 'react-emoji-render';
import emoji.css;
const emoji = () => {
return ( <Twemoji className="Twemoji" text=":+1:"/> );
}
export default emoji;
My css file (emoji.css) has the following code
.Twemoji {
width: 20em;
height: 20em;
}
but the size of the emoji doesn't change.
if I inspect the element and modify the inline style in the page html that works
Please can you help me understand how I can increase the emoji size via CSS
Twemoji Component does not take a prop className (see here), instead you will have to use the options prop in order to pass a custom css classname
const options = { className: "Twemoji" };
const emoji = () => {
return ( <Twemoji text=":+1:" options={options} /> );
}
EDIT:
you would also have to add !important to width and height in the css class to take precedence over the element style (see css precedence)
.Twemoji {
width: 4em !important;
height: 4em !important;
}

How can I set background image by dynamic names with styled-component?

I'm trying to set background-image with styled component. In the code below, I want to set background image with different divs, with img_01, img_02, img_03, .....
I saw many cases importing img path and use that, but I want to use dynamic name depending on the variable. Do I need to import all the images and set each of them?
import styled, { css } from 'styled-components';
const Div1 = styled.div`
width: ${props => props.width};
background: url('asset/images/img_0${props=>props.num}.png');
`;
class Main extends Component {
render() {
return (
<div>
<Div1 width={"475px"} num={1}>
</Div1>
<Div1 width={"154px"} num={2}>
</Div1>
</div>
)
}
}
How Can I do that without importing all ?
You can write it like that :
const Div1 = styled.div`
width: ${props => props.width};
background-image: ${props => `url('asset/images/img_0${props.num}.png')`};
`;

How to properly overwrite existing className with emotionJS

I'm trying to use emotion to overwrite the styling of an existing React component from a 3rd party library.
I try my best to simplified the problem in this codesandbox
The ExternalLib simulates a 3rd party component I'm using which I should not change the code.
As you can see it accepts a "prefix" props for css namespace and uses className in static string.(the original one has it as sass variable also)
I first try to get the base className hash with css function, then I try to compose those in emotion way of composition, and I get the expected visual result.
const baseStyle = css`
background-color: blue;
width: 200px;
height: 200px;
`;
const getItemStyle = ({ disabled }) => {
return `
height: 50px;
margin: 4px;
background-color: ${disabled ? "gray" : "yellow"};
`;
};
const getTextStyle = ({ color }) => {
return `
color: ${color}
`;
};
const StyledExternalLib = styled(ExternalLib)`
.${baseStyle}-track {
${getItemStyle};
}
.${baseStyle}-text {
${getTextStyle};
}
`;
however inspecting the style tags, I got many duplicated styles, what am I doing wrong?
you can see there are twice the yellow background
Here what i found, use css prop to the parent tag
css={{
"& .class__youwant--overwrite": {
margin: 80
}
}}
Worked in my case

Resources