Question about mixing styled-components with material-ui - reactjs

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;
}

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;

styled-components with custom React components: passing props

I have a custom component that takes in a property icon and sets the button's inner image to the corresponding icon as follows:
<custom-button-icon ref={showIcon} slot="right" icon="tier1:visibility-show" onClick={() => isPasswordVisible(false)} />
I would like to apply custom styling to a couple of instances of this component using styled-components. How can I pass the icon prop in so that it still functions (gets passed in as a pop of custom-button-icon)? This is what I have so far but it returns an empty button (with no icon):
export const d2lButtonIcon = ({ icon }) => {
const buttonIcon = styled(`d2l-button-icon`)`
display: flex;
align-items: center;
justify-content: center;
padding: 100px;
margin: 1px;
`
return <buttonIcon icon={icon} />
}
Thanks!
This is a really unusually case because this d2l-button-icon that you are dealing with a custom HTML element rather than a React component.
styled-components can style any React component and any built-in DOM element (a, div, etc.), but I don't think it knows how to deal with a custom DOM element because that's just not the way that we build things in React.
At first I tried passing the style to the d2l-button-icon element, and I got the icon prop to pass through but the style was ignored.
The way that I got this to work is to apply the styles to a div around the element and pass the other props to the d2l-button-icon element itself.
// function component adds styles around the icon button
const UnstyledD2L = ({ className, ...props }) => {
return (
<div className={className}>
<d2l-button-icon {...props} />
</div>
);
};
// can use styled-component to style this wrapper component
const StyledButtonIcon = styled(UnstyledD2L)`
display: flex;
align-items: center;
justify-content: center;
padding: 100px;
margin: 1px;
`;
// example usage with props
export default () => <StyledButtonIcon text="My Button" icon="tier1:gear" />;
However if you aren't super attached to this Brightspace package, I would recommend switching to a UI library that is designed for React.

pass props to styled-components selector

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' : ''};
`;

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

Styles are not working in through styled components

I am trying to add background-color through styled component.
If add the styles through style={} attribute it is working as expected but If I add the same style in my styled component file it is not working.
//this is working
<MyStyle style={{backgroundColor: '#fff' }}>
//some component here
</MyStyle>
//This is not working.
export const MyStyle = styled.div`
background-color: ‘#fff’;
`;
Can somebody point me here what I am missing here?
The first example is simply using the react style builtin, you don't need styled components to do this.
The code in the second example, you need to remove the quotes around the color, like this:
//This is not working.
export const MyStyle = styled.div`
background-color: #fff;
`;
Styled components takes css syntax, which unlike json syntax, does not have quotes around option names, color names, etc.
You don't have to put single quote around #fff
export const MyStyle = styled.div`
background-color: #fff;
`;
EDITED:
If there are overriding CSS styles that make your div's background not white just yet, and you can't find them, just add !important to this style
export const MyStyle = styled.div`
background-color: #fff !important;
`;
Regarding the issue about finding existing CSS styles that might be overriding your preferred style, take a look at this: https://www.styled-components.com/docs/advanced#existing-css

Resources