pass props to styled-components selector - reactjs

I've got a styled-component which gets some additional styles based on a property (active).
The component looks similar to this:
import styled from 'styled-components';
const Button = styled.button`
color: black;
${props => props.active ? `color: red;` : ''}
`;
Within a component test I need to select the active Button which (obviously) doesn't work doing the following:
document.querySelector(Button)
since this targets all Button components, no matter if active or not.
I read the styled-components docs and googled a lot. However I haven't been able to find a way to pass specific props to the styled-components-selector. I expected something similar to the following (which does not work)
document.querySelector(Button({ active: true }))
Is there any way to achieve this or rather how do you select a styled component which has specific props?

I think I've found a solution which is probably the 'right' way when using styled-components.
Instead of defining the active style via props within the button component, I've created another one which extends the button. This of course forces me to use another component for the active button instead of just setting an active property.
However it's not much additional work and super easy to test. So I've decided to go this way.
const Button = styled.button`
color: black;
`;
const ActiveButton = styled(Button)`
color: red;
`;
document.querySelector(ActiveButton);

The correct syntax is this:
const Button = styled.button`
color: black;
color: ${props => props.active ? 'red' : ''};
`;

Related

styled-components — how to use :not() selector on a prop?

Let's say I have an element with a property "selected":
<Button selected>
Text
</Button>
const Button = styled.div`
&:not(???) {
color: red;
}
`;
How do I select all instances of Button which don't have the "selected" property?
Maybe there is another way to do what I'm trying to achieve?
Сlarification edit:
I actually need to use :not together with :hover, like this:
const Button = styled.div`
&:not(???):hover {
color: red;
}
`;
styled-components uses some template magic to allow you to access passed props like so:
const Button = styled.div`
color: ${props => props.selected ? "color when selected" : "red"};
`;
With styled-components, this tends to be the more idiomatic way of setting things based on props rather than using CSS selectors.
That's how you can do it:
const Button = styled.div`
${props => !props.selected && css`
:hover {
color: red;
}`
}
`;
Don't forget to import css from styled-components;

Typescript says a prop does not exist on a component I wrapped with styled-components

I am using semantic-ui-react and along with styled-components. I am wrapping the Tab component with styled-components to customize its look. Here is that code
const CustomTab = styled(Tab)<{props: TabProps}>`
flex: 1;
display: flex;
margin-top: 10px;
flex-direction: column;
`;
As you can see I am trying to specify that the props for CustomTab will be the same props as the Tab component. I did this based on this answer.
The problem is that typescript still seems to think that Menu props does not exits on my CustomTab component.
Where am I going wrong?
Try const CustomTab = styled(Tab)<TabProps>
You basically defined your props as an object that looks like this: {props: {TabProps}}

Question about mixing styled-components with material-ui

Hello I am a react newbie and new to styling as well :)
I am trying to style the material-ui Button component with styled components
I am doing this by overriding global class names, I know material-ui introduced global class names like MuiButton-root etc
I am not clear on the use of "&" in parent selector, for example:
const StyledButton = styled(Button)`
&.MuiButton-root {
width: 500px;
}
.MuiButton-label {
color: ${props => props.labelColor};
justify-content: center;
}
`;
The above code works and can achieve the following:
The Button has a width of 500px
The label has a color of red (labelColor is passed in as a prop)
Please see sandbox below for full code
Question:
Why do I need "&" selector for the MuiButton-root, whereas for the MuiButton-label I don't?
Also is this the best way to style material-ui with styled components?
Please see the following sandbox: https://codesandbox.io/embed/practical-field-sfxcu
The '&' selector is used to target the classes and neighbouring elements/classes. Take a look at cssinjs. Its the underlying system behind MUI's styling.
But in short to answer your question;
const StyledButton = styled(Button)`
&.MuiButton-root { //this targets any class that is added to the main component [1]
width: 500px;
}
.MuiButton-label { //in css-in-js this is effectively '& .MuiButton-label [2]
color: ${props => props.labelColor};
justify-content: center;
}
[1] Targets main classes on component
<StyledButton className='test bob'> << this element is targeted
</StyledButton>
[2] Targets child elements either through class or element type. Note the space between & and the actual class.
<StyledButton className='test bob'>
<span className='MuiButton-label'>test</span> << this element is targeted instead
</StyledButton>
You can also use the element tag directly
span {
color: ${props => props.labelColor};
justify-content: center;
}

Emotion.js how to do composition / conditional styling in react-native?

https://github.com/emotion-js/emotion/tree/master/packages/native
gives example
style={css`
border-radius: 10px;
`}
However, I can't figure out how I can do composition as done in https://emotion.sh/docs/composition with react-native
<div css={[danger, base]}>
Nor I can't do conditional styling as done in https://emotion.sh/docs/styled
const Button = styled.button`
color: ${props =>
props.primary ? 'hotpink' : 'turquoise'};
`
Even if I could do, they use two different methods one using css one using styled . How can I get the two at the same time with react-native?
Question 1: How to do composition in emotion/native in React Native?
It's really simple all you need to is use style property like so:
const style1 = css`
font-size: 40px;
`
const color = css`
color: red;
`
// And then in your component you can pass the all your style objects
// in an array to style property
<Text style={[fontSize, color]}>Hello world</Text>
Question 2: Conditional style in emotion/native in React Native?
const Description = styled.Text`
font-size: ${props => props.fontSize !== undefined ? props.fontSize : "40px"};
color: hotpink;
`
<Description fontSize={"60px"}>
Change code in the editor and watch it change on your phone! Save to get a shareable url.
</Description>
Here's a working exampe as a snack

Styled components for colored tags

Styled components looks great, but I am having trouble organizing my components. My first venture with is a tag list, that automatically colors the tags. After some trial I came up with a component that can be used like this:
// An array of tags. The string hashes determine the color
<ColorTags tags={post.frontmatter.tags} inline/>
It is implemented as follows:
components/
ColorTags // functional component
ColorTagLI // styled component
ColorTagUL // styled component
With:
// ColorTags
import ColorTagLI from './ColorTagLI'
import ColorTagUL from './ColorTagUL'
export default ({tags, inline}) =>
<ColorTagUL>
{tags.map( tag =>
<ColorTagLI key={tag} colorString={tag} inline>
<Link to="/">
{tag}
</Link>
</ColorTagLI>
)}
</ColorTagUL>
// ColorTagUL
export default styled.ul`
list-style-type: none;
margin: 0;
padding: 0;
`
// ColorTagLI
const colorHash = new ColorHash({lightness: [0.4, 0.5, 0.6]});
const hslColor = cString => {
const [h, s, l] = colorHash.hsl(cString)
return `hsl(${h}, ${s*100}%, ${l*100}%)`
}
export default styled.li`
color: white;
background-color: ${props => hslColor(props.colorString)};
display: ${props => props.inline ? 'inline-block' : 'block'};
padding: 0.25rem 0.5rem;
margin: 0.25rem;
> a { text-decoration: none; color: white; }
`
Some questions I have:
What's a good way to discern between styled and regular components? I
decided on appending the HTML tag to the styled components, since
they are always tied to that.
Is it not a problem to have the Link tag inside a Styled component?
Should the ColorTag components be in a folder of themselves? Because they are tightly coupled.
Is using theinline prop a smart way to switch between configurations? It may
result in a lot of conditional statements for margins, padding and
media queries... Perhaps better make two different components?
You can use utility function isStyledComponent.
Why would it be a problem to have a Link component inside styled component?
Matter of opinion, if you believe they are tightly coupled you can create /ColorTag directory with index.js file that exports only what should be exposed.
Yes it may result in a lot of conditional statements, that's why you can extend styles on styled components.
I hope I understood you right and my answers are clear.

Resources