Conditionally add styles properties on MUI - material-ui

On styled-components we can have something like this
import syled, { css } from 'styled-components';
const StyledButton = styled.button<StyledButtonProps>`
display: flex;
${textStyles.styledButton}
${props =>
props.disabled &&
css`
opacity: 0.5;
`}
`
I'm trying to use MUI's styled but can't find how to conditionally add the opacity property based on the props passed to the button. I'm trying something like this, but don't want to define the default value of every conditional styles as on opacity here (since there could be a LOT of conditional properties based on the value of a passed prop)
import { styled } from '#material-ui/core/styles';
// eslint-disable-next-line #typescript-eslint/no-unused-vars
const StyledMUIButton = styled(({ disabled, disclosure, whiteButton, fullWidth, noMarginTop, ...rest }: StyledButtonProps) => (
<button {...rest} />
))({
display: 'flex',
...textStyles.button,
opacity: (props: StyledButtonProps) => props.disabled ? 0.5 : 1
})
Another case would be something like this in styled-components, how can be that applied to MUI's styled?
${props =>
props.whiteButton
? css`
background-color: transparent;
border: none;
${textStyles.styledLink}
`
: css`
&:focus {
background: transparent;
border: 1px solid ${colors.textLink};
color: ${colors.textLink};
}
`}

I ended up using makeStyles the following way
const useStyles = makeStyles({
button: (props: StyledButtonProps) => ({
display: 'flex',
...textStyles.button,
...props.disabled && { opacity: 0.5 },
})
})

Related

Styles not getting applied when I upgrade to Material UI 5 for elements

I recently upgraded my Material UI from V4 to 5 and stuck with a truckload of issues. One of them is that the styles are messing up when i move away from JSS
The arrow icon need to get the styles and the styles are not getting applied.
const StyledPopper = styled(Popper)(({ theme }) => {
return {
[`&.${classes.popper}`]: {
top: "100px !important",
left: "200px !important",
zIndex: 1,
'&[x-placement*="bottom"] $arrow': {
// is not getting applied
marginTop: theme.spacing(-5.25),
"&::before": {
borderWidth: "0 1em 1em 1em",
borderColor: `transparent transparent red transparent`
}
}
},
[`& .${classes.arrow}`]: {
position: "absolute",
"&::before": {
content: '""',
display: "block",
borderStyle: "solid"
}
}
};
});
<StyledPopper
open
placement="bottom-end"
anchorEl={
document && document.getElementById("location-confirmer-desktop")
}
modifiers={{ arrow: { enabled: true, element: arrowRef } }}
className={classes.popper}
>
<Box ref={setArrowRef} className={classes.arrow} />
<Box>This is the content</Box>
</StyledPopper>
https://codesandbox.io/s/combobox-demo-material-ui-forked-v5-8-4-g0pyhg?file=/demo.tsx

Material UI Display property not hiding content

Material UI explains Display in their docs as a way to Quickly and responsively toggle the display value of components!
I have an icon that i want it to be hidden on xs. I am trying
display={{ xs: 'none', sm: 'block' }} its not working.
I am trying display='none' just to see if it hides, also not working. If i set a className={classes.icon} and then i create an icon class in useStyles
icon: {
display: none,
},
the icon is hidden.
The behaviour is making me go crazy but am sure i am missing a concept on how these things rended or something is overriding the behaviour.
Also i dont know how to use display={{ xs: 'none', sm: 'block' }} inside the useStyle as double brackets are not allowed there
Here is full code:
const useStyles = makeStyles((theme) => ({
icon: {
paddingRight: 10,
color: 'white',
display: 'none', //setting this hides the icon
},
}
<Grid item container xs={12}>
<AccountBalanceIcon fontSize='large' className={classes.icon} display={{ xs: 'none', sm: 'block' }}/>
</Grid>
You can hide the AdbIcon when the screen's width becomes xs by using [theme.breakpoints.only("xs")] in the useStyles hook :-
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import {
Box
} from '#material-ui/core';
import AdbIcon from '#material-ui/icons/Adb';
const useStyles = makeStyles((theme) => ({
icon: {
color: 'red',
[theme.breakpoints.only("xs")]: {
display: "none",
},
}
}));
export default function ButtonSizes() {
const classes = useStyles();
return (
<AdbIcon
fontSize="large"
className={classes.icon}
/>
);
}
Read about all the breakpoint queries that are given by material-ui here
'display' property belongs to 'Box' component, not the Icon component.. I.e. the Icon must be wrapped in the Box component. The following sample works:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import {
Box
} from '#material-ui/core';
import AdbIcon from '#material-ui/icons/Adb';
const useStyles = makeStyles((theme) => ({
icon: {
color: 'red',
//display: 'none',
}
}));
export default function ButtonSizes() {
const classes = useStyles();
return (
<Box
display="block"
//display="none"
>
<AdbIcon
fontSize="large"
className={classes.icon}
/>
</Box>
);
}

Material-UI Style Override?

I'm updating my app from Material-UI v1 to v2. I'm trying to use a style override to set the color of a selected <BottomNavigationAction> element.
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100'
},
'&$selected': {
color: "#00bcd4" //<==trying to add this color to selected items
},
};
class bottom_nav extends Component {
state = {
selectedIndex: -1,
};
handleChange = (event, value) => {
this.setState({value});
};
render() {
const { classes } = this.props;
return (
<Paper className={classes.bottomNavStyle}>
<BottomNavigation
value={this.props.selectedBottomNavIndex}
onChange={this.handleChange}
showLabels
>
<BottomNavigationAction
label="Appointments"
icon={theApptsIcon}
/>
<BottomNavigationAction
label="Contacts"
icon={theEmailIcon}
/>
<BottomNavigationAction
label="Video Call"
icon={theVideoCall}
/>
</BottomNavigation>
</Paper>
);
}
}
export default withStyles(styles)(bottom_nav);
But, this does not do anything to the color of selected items.
I've read the Material-UI docs on CSS in JS and JSS, but haven't quite gotten it yet. What is the correct syntax for this?
UPDATE
Based on a response to this thread I've tried this:
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100'
},
actionItemStyle: {
'&$selected': {
color: "#00bcd4 !important"
},
},
}
[.....]
return (
<Paper className={classes.bottomNavStyle}>
<BottomNavigation
value={this.props.selectedBottomNavIndex}
onChange={this.handleChange}
showLabels
>
<BottomNavigationAction
label="Appointments"
icon={theApptsIcon}
className={classes.actionItemStyle}
/>
<BottomNavigationAction
label="Contacts"
icon={theEmailIcon}
className={classes.actionItemStyle}
/>
<BottomNavigationAction
label="Video Call"
icon={theVideoCall}
className={classes.actionItemStyle}
/>
</BottomNavigation>
</Paper>
);
}
...but have not yet gotten the new color to appear on the web page.
Your updated solution looks good, there are just a few small changes...
You need to include an empty .selected class in your styles rules.
const styles = {
// Root styles for `BottomNavigationAction` component
actionItemStyles: {
"&$selected": {
color: "red"
}
},
// This is required for the '&$selected' selector to work
selected: {}
};
You need to pass classes={{selected: classes.selected}} to BottomNavigationAction. This is required for the '&$selected' selector to work.
<BottomNavigation
value={value}
onChange={this.handleChange}
className={classes.root}
>
<BottomNavigationAction
classes={{
root: classes.actionItemStyles,
selected: classes.selected
}}
label="Recents"
value="recents"
icon={<RestoreIcon />}
/>
</BottomNavigation>
Live Example:
There are couple of things I would like to suggest.
1) Write the name of the component with first letter capitalized since it is not treated the same way if it is named with small first letter and with capitalized.
2) If there is no other way for your cs rule to be applied, if it is overridden always because of some css specificity, use !iportant at the end of the rule.
3) Try this type of nesting of css in jss:
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100',
'&:selected': {
color: "#00bcd4"
},
},
};

Styling react-select v2 with material-ui - Replace Input component

I'm having an issue with replacing the Input component for react-select v2 with the Input component from Material UI.
I've made an attempt so far in the codesandbox below, but unable to invoke the filtering upon typing into the Input?
https://codesandbox.io/s/jjjwoj3yz9
Also, any feedback on the Option replacement implementation would be appreciated. Am I going about it the right way with grabbing the text of the clicked option and search for the Option object from my options list to pass to the selectOption function?
Much appreciated,
Eric
V1
refer the documentation from here : https://material-ui.com/demos/autocomplete/
it provides clear documentation about how to use react-select with material-ui
here is a working example for your question: https://codesandbox.io/s/p9jpl9l827
as you can see material-ui Input component can take react-select as inputComponent.
V2
It's almost same as the previous approach :
implement the Input component:
<div className={classes.root}>
<Input
fullWidth
inputComponent={SelectWrapped}
value={this.state.value}
onChange={this.handleChange}
placeholder="Search your color"
id="react-select-single"
inputProps={{
options: colourOptions
}}
/>
</div>
and then SelectWrapped component implementation should be:
function SelectWrapped(props) {
const { classes, ...other } = props;
return (
<Select
components={{
Option: Option,
DropdownIndicator: ArrowDropDownIcon
}}
styles={customStyles}
isClearable={true}
{...other}
/>
);
}
and I overrides the component Option and DropdownIndicator to make it more material and added customStyles also:
const customStyles = {
control: () => ({
display: "flex",
alignItems: "center",
border: 0,
height: "auto",
background: "transparent",
"&:hover": {
boxShadow: "none"
}
}),
menu: () => ({
backgroundColor: "white",
boxShadow: "1px 2px 6px #888888", // should be changed as material-ui
position: "absolute",
left: 0,
top: `calc(100% + 1px)`,
width: "100%",
zIndex: 2,
maxHeight: ITEM_HEIGHT * 4.5
}),
menuList: () => ({
maxHeight: ITEM_HEIGHT * 4.5,
overflowY: "auto"
})
};
and Option:
class Option extends React.Component {
handleClick = event => {
this.props.selectOption(this.props.data, event);
};
render() {
const { children, isFocused, isSelected, onFocus } = this.props;
console.log(this.props);
return (
<MenuItem
onFocus={onFocus}
selected={isFocused}
onClick={this.handleClick}
component="div"
style={{
fontWeight: isSelected ? 500 : 400
}}
>
{children}
</MenuItem>
);
}
}
please find the example from here: https://codesandbox.io/s/7k82j5j1qx
refer the documentation from react select and you can add more changes if you wish.
hope these will help you.

Apply CSS to Typography Material UI

Im trying to apply css to a Typography element but it does nothing; I have tried the same css on another div element and it works but it simply does not apply to Typography.
This is my Typography element:
<Typography
variant="title"
classname={classes.detailTitle}
>
Details:
</Typography>
And this is my css:
detailTitle: {
textDecoration: 'underline'
}
Any clues?
You have a slight typo in your Typography html, it needs to say className where you have classname. This is react specific, for more info take a look here https://reactjs.org/docs/dom-elements.html
You can use Material UI component's classes property to set its style.
Check this page https://material-ui.com/api/typography/#css
Example:
const useStyles = makeStyles((theme) => ({
h3: {
fontSize: '48px',
fontWeight: '600'
},
})
)
const TextComp = (props) => {
const classes = useStyles()
return (
<Typography
variant='h3' component='h3'
classes={{ h3: internalClasses.h3 }}
>
{header}
</Typography>
)
}