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

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;

Related

Styled-Components Pass Props For Condition

I am trying to make a conditional icon with styled-components. But I need to pass props like function params. Because I need to change the icon with the condition.
export const RadioCheck = ({checked}) => styled(checked ? FaCheckCircle : FaRegCircle)`
display: flex;
align-self: center;
margin: 0 2em;
font-size: 1em;
color: ${props => props.checked ? primary : `transparent`}
`
Is there any way for this or I need to create two different components and use them?
Seems to me like you should use the condition where you return the icon to decide which component to use.
Something like
return(
<div>
{checked ?
<FaCheckCircle
//... your props
/>
:
<FaRegCircle
//... props
/>
}
</div>
)
If it's helpful to you, it is possible to style a styled component, such as
const FirstComponent = styled.div`
//some styling
`
const SecondComponent = styled(FirstComponent)`
//some more styling
`

Styled component ReactJs

export const RedHeader = styled.div`
color: red;
border: 1px solid blue;
background-color: gray;
`;
function Header(className) {
return (
<RedHeader className={className}>
this is styled component example
<p>test</p>
</RedHeader>
)
}
export default Header;
I have red the cdocumentation but i can't figure out, why should we use className as a props and after that in className={className}?
When using styled components, there should be no need to use className (which renders as class attribute in HTML) anymore. In your example, you pass className to the styled component, but the styled component does not use it in any way.
You can pass properties to your styled components if you want dynamic styling like you would do with class names in classic CSS.
Example with style that depends on a class name:
const RedHeader = styled.div`
color: red;
&.active {
color: blue;
}
`
Example with props:
const RedHeader = styled.div`
color: ${props => props.active ? 'blue' : 'red'}
`
function Header({ active }) {
return (
<RedHeader active={active}>
example
</RedHeader>
)
}

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

How to inherit style from another component?

I want to take styling from the component 'Tab' which is a react-router-dom Navlink and apply it to my new component 'DropdownTab' which is a 'div'. How can I inherit the styling without making it a NavLink? I want to do this to avoid duplicate lines of code.
const Tab = styled(NavLink)`
padding: 0 20px;
height: ${variables.height};
line-height: ${variables.height};
`;
// Should be the component 'Menu' and is now the component NavLink
const DropdownTab = styled(Tab)`
`;
Perhaps you can use as?
const DropdownTab = styled(props => <Tab as="div" {...props} />)`
/* additional styles */
`;
That's ugly though, so maybe you can just extract the common styles into a variable:
const commonStyles = `
/* common styles */
`
const Tab = styled(NavLink)`${commonStyles}`
const DropdownTab = styled('div')`${commonStyles}`
If you have prop-based style in your component (i.e color: ${props => props.color}, you'd need to use css helper:
import styled, { css } from 'styled-components'
const commonStyles = css`
color: ${({ isActive }) => isActive ? 'red' : 'blue' };
`
...
Why is DropdownTab a div?
Based on your code, DropdownTab is a Tab. You've used the extending styles concept of styled-components and you've done it right.

Best way to style a component?

I have two solutions to style my component. Which one is the better choice?
First option is to set everything in the styled component.
Second option is to use many container and styles one by one containers.
First option:
export const BaseContainer = styled.div`
span {
color: #E0E0E0;
}
i {
margin-right: 16px;
}
`;
<BaseContainer data-testid="base">
<i className="icon-share" />
<span> {base} </span>
</BaseContainer>
Second option:
export const BaseContainer = styled.div`
color: #E0E0E0;
`;
export const IconContainer = styled.div`
margin-right: 16px;
`;
<IconContainer>
<i className="icon-share" />
</IconContainer>
<BaseContainer data-testid="base">
{base}
</BaseContainer>
I would go for the second option as the first option ties together 2 elements in one div and if you would want to use the same css properties in another case would require refactoring.
But be aware that your second option is not really a small difference from the first:
In your first option you have one div with one i and one span inside of it and you are applying style to i and span correspondingly.
In your second option you have 2 separate div one with one i and the other with just a content and you are applying style to both div instead.
That said, the best solution would be to actually style the span and i individually, something like
const StyledSpan = styled.span`
color: #E0E0E0;
`
const StyledIcon = styled.i`
margin-right: 16px;
`
And then use them as:
<div data-testid="base">
<StyledIcon className="icon-share" />
<StyledSpan>{base}</StyledSpan>
</div>
I think it's a bit opinion based, but I would approach this a manner like this:
const IconContainer = styled.i`
margin-right:16px;
`;
const Icon = ({
iconType,
...props}) => <IconContainer className={ `icon-${iconType}` } {...props } />;
const BaseContainer = styled.div`
color: #E0E0E0;
`;
const LabelledIcon = ({ iconType, ...props }) => <BaseContainer>
<Icon iconType={ iconType } />
{ props.children }
</BaseContainer>;
// usage:
<LabelledIcon iconType="share"> icon label text </LabelledIcon>

Resources