How to use conditional styles with MUI v5 using emotion styled - reactjs

I'm migrating from MUI v4 to v5. In v4 I was using clsx with TextField to add conditional styles.
export const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
// ...
},
valid: {
"& fieldset": {
borderColor: theme.palette.success.main,
borderWidth: 2
}
}
})
);
const classes = useStyles();
<TextField
{...props}
className={clsx(classes.root, { [classes.valid]: isValid })}
/>
I'm trying to find a similar approach in MUI v5. Is there any alternative for conditional styles in MUI v5 other than with clsx and makestyles.
Let me know if more information is required.

There are multiple ways to do that:
1. Conditional operator
Use this if you want to conditionally set a property based on a boolean value.
const Box1 = styled(Box, {
shouldForwardProp: (prop) => prop !== "showBorder"
})(({ showBorder }) => ({
border: showBorder ? "solid red 5px" : "none"
}));
<Box1 />
<Box1 showBorder />
2. Dictionary
Use this if you want to conditionally set a property based on multiple values.
import { styled, darken } from "#mui/material/styles";
const colors = {
hauntedForest: "#0b5b38",
redLust: "#b20608",
spaceExplorer: "#1244a1",
default: "#000000"
};
const Box2 = styled(Box, {
shouldForwardProp: (prop) => prop !== "variant"
})(({ variant }) => ({
backgroundColor: colors[variant] ?? colors.default,
border: "5px solid " + darken(colors[variant] ?? colors.default, 0.3)
}));
<Box2 variant="hauntedForest" />
<Box2 variant="redLust" />
<Box2 variant="spaceExplorer" />
<Box2 />
3. Short-circuit evaluation + Spread operator
Use this if you want to conditionally set multiple properties.
const Box3 = styled(Box, {
shouldForwardProp: (prop) => prop !== "isFancy" && prop !== "isFancyBorder"
})(({ theme, isFancy, isFancyBorder }) => ({
...(isFancy && {
borderRadius: theme.shape.borderRadius,
boxShadow: "0 4px 6px gray, 0 1px 3px rgba(0, 0, 0, 0.08)",
backgroundImage: "linear-gradient(90deg, #be5af7, #165b91)"
}),
...(isFancyBorder && {
backgroundColor: "transparent",
border: "5px solid transparent",
borderImage: "linear-gradient(90deg, #be5af7, #165b91)",
borderImageSlice: 1
})
}));
<Box3 isFancy />
<Box3 isFancyBorder />
All of the methods above can also be applied when using sx props since they use JS object to describe the styles.
Live Demo

This seem to work for me
Using sx
sx={{ px: variable ? 8 : null }}
sx with breakpoint
sx={{ px: { md: variable ? 8 : null } }}
prop
<Typography align={variable ? 'center' : 'inherit'}>
Using className
className={ variable ||'class-name'}

Related

Passing sx prop to a custom component

I have a component that I use as a layout component, and in nearly all cases it works just fine, however there are one or two places where I need to be able to adjust the styles, and I would like to be able to do this by simply passing the exact styles that I need instead of adding some custom prop that will toggle them on or off.
The component looks like this:
const BlockLayout: React.FC<IProps> = ({
children,
id,
forceToBottom,
sxProps, // <--- What I want to add
}) => {
return (
<Box
id={id}
sx={[
{
backgroundColor: (theme) => theme.palette.background.paper,
mt: forceToBottom ? 'auto' : 1,
borderRadius: 0.5,
display: 'flex',
border: '1px solid rgba(0, 0, 0, 0.1)',
flexWrap: 'wrap-reverse',
},
sxProps, //<--- How I could use it?
(theme) => ({
...(theme.palette.mode === 'dark' && {
border: `1px solid ${lighten(
theme.palette.background.paper,
0.15
)}`,
}),
}),
]}
>
{children}
</Box>
)
}
How can this be done, and what type do the props need to have?
In the documentation they just cast the type to const.
You can add them as follows using the spread operator:
},
sxProps && ...sxProps,
(theme) => ({

Changing the arrow/icon colour material ui select

I'm trying to change my icon to white
Here is my current code but not sure how to change icon colour property:
Link to codesandbox sample
<NativeSelect
disableUnderline
style={{
paddingLeft: 10,
borderRadius: 20,
color: "white",
background: "#121c30",
boxShadow: "0px 5px 8px -3px rgba(99,0,0,0.14)",
}}
defaultValue={"Last 7 days"}
onChange={handleChange}
>
......
</NativeSelect>
The material provides you, one class, for changing the color of that icon.
.MuiNativeSelect-icon {
color: red
}
const MyIcon = (props)=> {
const { style, ...otherProps } = props;
const colorStyle = {
color: 'white',
};
const styles = { ...style, ...colorStyle };
return <ArrowDropDownIcon {...otherProps} style={styles} />
}
<NativeSelect
IconComponent={MyIcon}
...
/>
I would recommend not to use inline styles, as you cannot apply them in classes property, in your case this should work for you
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
iconSelect: {
color: "white"
},
});
...
export default function App() {
const classes = useStyles();
...
<NativeSelect
disableUnderline
classes={{icon: classes.iconSelect}}
...
>
https://codesandbox.io/s/table-forked-7w6nw
Create .css, where is your choice.
there. instead of writing: color:white; you can write color:white !important;

How to change the progress bar background color dynamically in react material ui?

//Component Style:
const BorderLinearProgress = withStyles(theme => ({
bar: {
borderRadius: 8,
backgroundColor: "red"
}
}))(LinearProgress);
//Component use:
<BorderLinearProgress variant="determinate" value={50} />
I am new to react and material-ui.
In the above code I need to pass or change bar:backgroundColor dynamically.
Please let me know what are the options to do.
Thanks in advance
You can pass your color with the theme variable.
// Passing theme
const useStyles = makeStyles((theme) => ({
bar: props => ({
borderRadius: 8,
backgroundColor: props.color
})
}))
//Using style in component
...
const [progressColor, setProgressColor] = React.useState({ color: 'red' })
const classes = useStyles(progressColor);
// Update color based on your requirements i.e. setProgressColor({color: 'green'}) in some useEffect() when progress crosses some threshold
return (
<LinearProgress color={classes.bar} />
)
...
You can find an example in official docs: https://material-ui.com/styles/basics/#adapting-based-on-props
Below code works fine with dynamic values and colors
const LinearProgressBar: React.FC<ILinearProps> = ({ value, color }) => {
const useStyles = makeStyles({
root: {
height: 10,
borderRadius: 5
},
colorPrimary: {
backgroundColor: '#E9E9E9'
},
bar: {
borderRadius: 5,
backgroundColor: color
}
});
const classes = useStyles();
return (
<LinearProgress
variant="determinate"
value={value}
classes={{
root: classes.root,
colorPrimary: classes.colorPrimary,
bar: classes.bar
}}
/>
);
};
export default LinearProgressBar;
You can do it in two ways:
1). just Write
<LinearProgress style={{backgroundColor: "red"}} variant="determinate" value={50} />
2).
import React from 'react';
import { withStyles } from '#material-ui/core/styles';
const styles = {
LinerProgressColor: {
backgroundColor: 'red',
},
};
function BorderLinearProgress (props) {
return <LinearProgress className={LinerProgressColor} variant="determinate" value={50} />;
}
export default withStyles(styles)(BorderLinearProgress);

Changing MUI Chip primary or secondary color

I am trying to programmatically change the color of a MUI Chip without much luck. According to the Chip API you have to set the color via the color prop with one of three values from an enum; default, primary, and secondary. You should then be able to override the the colorPrimary or colorSecondary css classes and the background color should change.
Here is an example of my code:
<Chip key={label.id} color='primary' classes={{ colorPrimary: label.color }} label={label.label} />
And a picture of the element in browser:
https://i.imgur.com/bWYGzzz.png cant inline yet :(
If you look at the selected element, you will see the correct color I am trying to apply, #ff0000, so it is getting the color and putting it somewhere.
I've tried this variation, adding the colorBackground property, but I get an error saying the colorPrimary class expects a string instead of an object
<Chip key={label.id} color='primary' classes={{ colorPrimary: { backgroundColor: label.color } }} label={label.label} />
Again to reiterate my goal: I want to apply a hex code color to the chip to change the background color.
you can make it in many ways.
you can add styles directly
<Chip key={label.id} color='primary' style={{backgroundColor:'green'}} label={label.label} />
or you can override the class:
const StyleChip = withStyles({
root: {
backgroundColor:'salmon'
}
})(Chip);
to use everywhere you only will replace Chip to StyleChip
<StyleChip key={label.id} color='primary' label={label.label} />
but if you wanna put the color by programation, the first way is perfect, because
style={{backgroundColor:_thisCanBeVariable_}}
You can set the primary or secondary color of the Chip component easily using createTheme:
const theme = createTheme({
components: {
MuiChip: {
styleOverrides: {
colorPrimary: {
backgroundColor: 'red',
},
colorSecondary: {
backgroundColor: 'brown',
},
},
},
},
});
<Chip label="primary" color="primary" />
<Chip label="secondary" color="secondary" />
Or if you're using MUI v5, you can quickly change its color with the help of sx prop:
<Chip label="sx" sx={{ bgcolor: 'green', color: 'white' }} />
If you want to be able to specify different color via a prop, you can use styled:
const options = {
shouldForwardProp: (prop) => prop !== 'bgcolor',
};
const StyledChip = styled(
Chip,
options,
)(({ bgcolor }) => ({
color: 'white',
backgroundColor: bgcolor,
}));
<StyledChip label="styled" bgcolor="purple" />
For those trying to get this previous to the v5 (which would need to add a new color to the palette) a simple wrapper will get the job done:
import React from 'react';
import PropTypes from 'prop-types';
import MaterialChip from '#material-ui/core/Chip';
import { withStyles } from '#material-ui/core/styles';
const Chip = (props) => {
const StyledChip = withStyles({
root: {
'color': 'white',
'backgroundColor': `${props.color} !important`,
'&:hover': {
backgroundColor: props.color,
filter: 'brightness(120%)',
},
'&:active': {
boxShadow: 'none',
backgroundColor: props.color,
borderColor: props.color,
},
},
outlined: {
color: props.color,
border: `1px solid ${props.color}`,
backgroundColor: `transparent !important`,
},
icon: {
color: props.variant === 'outlined' ? props.color : 'white',
},
deleteIcon: {
color: props.variant === 'outlined' ? props.color : 'white',
},
})(MaterialChip);
return <StyledChip {...props} />;
};
Chip.propTypes = {
color: PropTypes.string,
variant: PropTypes.oneOf(['regular, outlined']),
};
export default Chip;

React Styling in Props

I did some styling for a material ui button and now I want to move the style={{backgroundColor}} part to the top of the function, right before the return.
Does someone know how to do that?
const styles = {
root: {
color: "#FFFFFF",
backgroundColor: "#05164D",
transition: "linear 0.5s",
"&:hover": {
opacity: 0.9,
boxShadow: "0 3px 5px 2px rgba(153, 153, 153, .8)"
}
}
};
const StyledButton = props => {
const { classes } = props;
let customColor = props.customColor || "#05164D";
let backgroundColor = customColor;
return (
<div>
<IconButton
className={classes.root}
{...props}
aria-label="StyledButton"
style={{ backgroundColor }}
/>
</div>
);
};
export default withStyles(styles)(StyledButton);
I think it is important to mention that {backgroundColor} is a shorthand for {backgroundColor: backgroundColor}. So in ES6 you can simply use the variable name, if the value of the property should be the same as the variable name. This variable is initialized within the curly braces, which wrap the property value. That's why it is {{ backgroundColor }}. If you want to initialze the variable above the render you can do it like this.
const StyledButton = props => {
const { classes } = props;
let customColor = props.customColor || "#05164D";
let style = { backgroundColor: customColor };
return (
<div>
<IconButton
className={classes.root}
{...props}
aria-label="StyledButton"
style={style}
/>
</div>
);
};

Resources