How to useStyles based on props inside a breakpoint with material-ui - reactjs

Let's say I have a very simple props interface that specifics a boolean property. Now, in my useStyles, I want to change how that style is rendered based on both the conditional property AND a breakpoint. Here's a very simple example:
interface Props {
isError: boolean;
}
const useStyles = makeStyles<Theme, Props>(theme => ({
box: ({ isError}) => ({
backgroundColor: isError? 'red' : 'green',
[theme.breakpoints.up('md')]: {
backgroundColor: isError ? 'maroon' : 'teal',
}
}),
}));
When I'm under the md breakpoint, this works as expected; but as soon as I go over the md breakpoint, the color doesn't change. How come?
Here's a demo on StackBlitz that demonstrates the problem.

In working up the example for this question, I figured out the problem. The property value for creating styles based on a breakpoint, also needs to be a function:
const useStyles = makeStyles<Theme, Props>(theme => ({
box: (outerProps) => ({
backgroundColor: outerProps.isError ? 'red' : 'green',
[theme.breakpoints.up('md')]: (innerProps) => ({
backgroundColor: innerProps.isError ? 'maroon' : 'aqua',
}),
})
}));
Here's an updated StackBlitz showing the working example.

Related

Material-UI: Customise theme for hover state

I am trying to customise MUI V5 theme to define colours of a design system for all components according to variant, color and state(hover).
I tried to follow the approach mentioned in: https://mui.com/blog/callback-support-in-style-overrides/ and it works fine when I tried it for MuiButton as shown below. but to apply the design system I have to write the same conditions for all defined components(Fab, chip, selector,...) with all supported colors and variants :
MuiButton: {
defaultProps: {
variant: 'contained',
},
styleOverrides:{
root: ({ ownerState, theme }) => ({
...(ownerState.color === 'error' && {
...(ownerState.variant === 'contained' &&{
'&:hover':{
backgroundColor: '#530F00',
}
}),
...(ownerState.variant === 'outlined' &&{
borderColor: '#D48E80',
'&:hover':{
backgroundColor: '#F8EDEB',
}
}),
}),
},
},
My question: Is there a general way to define styles for all components with same variants? Or is there a better way to achieve this?

Target CSS child selector created by in material ui

I have styles like this:
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red'
},
active: {
// here I want to target the 'container' className I created above like
'& .container': {
backgroundColor: 'green'
}
}
});
I want to target the container className I created inside of the active className. The above won't work because in the DOM, MUI will generate a unique name so I won't be targeting the right class. Wasn't able to find any SO answer or blog or documentation addressing this.
$ rulename is used for this purpose. Here is the documentation of it on Material-UI.
CSS in JS documentation also explains this feature.
container: {
//other styles
},
active: {
"& $container": {
background: "green",
color: "#fff"
}
}
Here one thing which is important that for referencing 'containerrule, it should be defined in the rules object. trying to use"& $containerwithout defining thecontainerrule inside themakeStyles` will not work.
Here is the working demo:
You can refer using $
You will have to modify your DOM little bit such that the active className is not the parent of container. Instead add the active className to the conatiner element itself.
so your css style might look like below
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red',
'&$active': {
backgroundColor: 'green'
}
},
});
I think this is what you are looking for $rulename
How to Use $ruleName to reference a local rule within the same style sheet
In your case i think the solution would be
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red'
},
active: {
.container: {
backgroundColor: 'green'
}
}
});
Which should compile to
.root.container.active{}
and on the target tag taking a example of button here
<Button
classes={{
root: classes.root,
container: classes.container,
active: classes.active,
}}>
Havent worked with MUI yet but even in vue or react the way this is achived is by setting a dynamic name on the tag that is targeted via script.

Remove (or at least hide) card on react-admin List

I want to get rid of the Card on the background react-admin's List (v3.4.2). I get the desired effect if I define a string on the component property:
<List component={"some string"}/>
But this spams the console with an error:
And I don't want to have that error. On top of that, I think I shouldn't be changing the component property (I can't find it on the official docs).
The code should be the following: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/list/List.js
How should I do this? Is it possible to pass a style? Is there any component that works out of the box? Or should I just go custom?
You can hide the background using styling:
import { makeStyles } from '#material-ui/core/styles'
const useListStyles = makeStyles(theme => ({
content: {
boxShadow: 'none',
backgroundColor: 'inherit',
},
main: {
// backgroundColor: 'red',
},
root: {
// backgroundColor: 'red',
},
}))
const MyList = (props) => {
const classes = useListStyles()
return (
<List classes={classes} {...props} >
...
</List>
)
}

How can I dynamically change property value in an object in Material UI?

I have property named listItem in useStyles defined outside of TodoListItem like this:
const useStyles = makeStyles(theme => ({
listItem: {
textDecoration: 'none'
}
})
)
const TodoListItem({checked}) => {
const classes = useStyles();
return <ListItemText className={classes.listItem} primary={text}/>
};
Then I wanted to change the status of textDecoration based on variable named checked.
And I tried to directly use checked variable in useStyles but does not work as it is out of scope.
textDecoration: checked ? 'line-through' : 'none'
In this case, how should I pass checked variable into useStyles to make the ternary operator working?
CSS properties in makeStyles support custom props for dynamic styling:
const useStyles = makeStyles(theme => ({
listItem: {
textDecoration: ({checked}) => checked ? 'line-through' : 'none'
}
}));
const Component = props => {
const classes = useStyles({checked: props.checked});
...
}
You can pass props, state, and whatever you want as a param to the style hook.
And it has better readability since we can understand whether the style hook is using other params or not quickly.
const useStyles = checked =>
makeStyles(theme => ({
listItem: {
textDecoration: checked ? 'line-through' : 'none'
}
}));
const classes = useStyles(checked)();
I think that the most easy way to achieve it is to use style instead classname and manipulate everything that will use logic outside big style object
<ListItemText style={[classes.listItem,{textDecoration: checked ? 'line-through' : 'none'}]} primary={text}/>

React Native - #emotion/native - TextInput placeholder text color attribute

I am trying to pass the placeholderTextColor attribute through the styled.TextInput.attrs function. The reason why I'm doing this is so I can access the theme props.
This is what I have:
const TextInput = styled.TextInput.attrs(props => ({
placeholderTextColor: "red",
type: "password"
}))`
color: ${({ theme }) => theme.colors.text};
`
But I am getting the following error:
_native.default.TextInput.attrs is not a function. (In '_native.default.TextInput.attrs(function (props) {
return {
placeholderTextColor: "red",
type: "password"
};
})', '_native.default.TextInput.attrs' is undefined)
I guess #emotion/native does not support the attrs function yet, so I moved over to styled-components.

Resources