Material-ui style type override - css

I'd like to modify MuiIconButton-root class when I use MuiSvgIcon with fontSizeSmall.
import React from 'react'
import { createMuiTheme, ThemeProvider } from '#material-ui/core/styles';
const theme = createMuiTheme({
overrides: {
MuiSvgIcon: {
fontSizeSmall: {
padding: "5px"
}
}
}
});
export default function Root(props) {
return (
<ThemeProvider theme={theme}>
<MyApp />
</ThemeProvider>
)
}
I've modified MuiSvgIcon, but it can't modify MuiButtonBase-root.
Is there any way to override the padding value of MuiIconButton-root when I use small MuiSvgIcon?
Following the picture:

yes you can override the style of root like this, I am not creating your exact scenario but I am going to show you the same functionality with a button from Material UI, first get all the files needed:
npm install #material-ui/styles
npm install #material-ui/core
and then:
//other react imports
import { makeStyles, withStyles } from '#material-ui/core/styles'; //you need to include this to change the style
import Button from '#material-ui/core/Button'; //this is just the button
const useStyles = theme => ({
root: {
'& > *': {
margin: theme.spacing(1),
},
},
button: {
fontSize: "16px",
fontWeight: "600",
textAlign: "center",
border: "none",
cursor: "pointer",
color: "#fff",
backgroundColor: "#C8385E"
}
});
class Welcome extends React.Component {
render() {
return (<div>
<Button
className={classes.button}
variant="contained" component="span">
BUTTON TEXT
</Button>
</div>);
}
}
export default withStyles(useStyles)(Welcome);
you need to export the class like shown above, include the "withStyles" and pass in the styles that you have, here its called "useStyles" and then pass the class name. this way you can edit the styles in the UseStyles and it will actually show those changes on the screen.

Related

How can I override styling for ListItemButton when it's selected?

I'm trying to override the existing styling for a button in MUI. This is my first time using MUI, and I installed my project with the default emotion as a styling engine. I tried to use the css() method as specified here : The css prop however it doesn't seem to be working, even on the example case provided.
I would have tried to add a custom css file to handle :select, but I'm using state in my component to change from selected to not selected.
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
import { css } from "#emotion/react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
css={css`
::selection {
color: #2e8b57;
}
:focus {
color:#2e8b57;
}
:active {
color:#2e8b57
}
`}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
Working examples on Code Sandbox
I have made a similar example using Code Sandbox, which you can find here https://codesandbox.io/s/amazing-gagarin-gvl66n. I show a working implementation using:
The css prop
The sx prop
Using the css prop
There's two things you need to do to make your code work using Emotion's css prop.
Add the following lines, which is also in the example, at the top of the file where you are using the css prop. This will tell your app how to handle the css prop.
/* eslint-disable react/react-in-jsx-scope -- Unaware of jsxImportSource */
/** #jsxImportSource #emotion/react */
Target the classes Material UI provides for the List Item Button component. For example, if I want to style the List Item Button when selected is true, I would target the .Mui-selected class.
I am assuming you wanted to style the background color of the List Item Button rather than the color. Styling the color changes the font color. However, if you wanted to change the font color, you can just change each instance of background-color to color.
Putting it altogether:
/* eslint-disable react/react-in-jsx-scope -- Unaware of jsxImportSource */
/** #jsxImportSource #emotion/react */
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
import { css } from "#emotion/react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
css={css`
&.Mui-selected {
background-color: #2e8b57;
}
&.Mui-focusVisible {
background-color: #2e8b57;
}
:hover {
background-color: #2e8b57;
}
`}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
Alternative: Using the SX prop
The sx prop can be used to override styles with all Material UI components. You are already using this for the Avatar and ListItemText components in your example.
Using the sx prop, the equivalent code would be:
import * as React from "react";
import Avatar from "#mui/material/Avatar";
import ListItemText from "#mui/material/ListItemText";
import ListItemButton from "#mui/material/ListItemButton";
import { useState } from "react";
const ProfileInfo = ({ userCredentials, userPicture }) => {
const [selected, setSelected] = useState(false);
return (
<ListItemButton
selected={selected}
onClick={() => setSelected((prev) => !prev)}
sx={{
"&.Mui-selected": {
backgroundColor: "#2e8b57"
},
"&.Mui-focusVisible": {
backgroundColor: "#2e8b57"
},
":hover": {
backgroundColor: "#2e8b57"
}
}}
>
<Avatar
alt={userCredentials}
src={userPicture}
sx={{ width: 24, height: 24 }}
/>
<ListItemText primary={userCredentials} sx={{ marginLeft: 3 }} />
</ListItemButton>
);
};
export default ProfileInfo;
It looks like MUI components doesn't use standard CSS rules but instead has a defined set of CSS rules you can modify https://mui.com/material-ui/api/list-item/#props.

React css renders correctly only on IDE refresh

I have some unexpected CSS behaviour that I don't understand - can anyone help me understand why it's happening, and help me get my CSS imports right?
I have a react app that uses a single component, that imports a stylesheet from a separate file brand.js. The component has an <Avatar className={classes.avatarTM}>; brand.js defines that class as having a backgroundColour of Dark Blue, which is what I'm expecting.
But when I load the app in Chrome, that avatar loads grey, not blue. Inspecting the element shows that two styles apply: .makeStyles-avatarTM-11 with the expected backgroundColor of primary.dark, and .MUIAvatar-colorDefault with backgroundColor #bdbdbd. colorDefault takes precedence on backgroundColor over avatarTM-11, so I get a grey avatar. This is not good.
If I then edit the // deleteme comment in brand.js in Visual Studio and save the file, React auto-refreshes the avatar in Chrome in Blue. avatarTM-11 is now taking precedence over colorDefault.
If I then reload the page in Chrome, it reloads as default grey.
But the bit that really screws up my attempts at bugfixing is that if I create a new file brand2.js, and copy/paste the exact content of brand.js into that new file, then modify the imports in App2.js and testComponent.js to import brand2 instead of brand, it works just fine. avatarTM-11 now takes precedence over default no matter what loads the page, and I get a blue avatar.
So just use brand2 instead of brand, right? Right. So I delete brand.js.... and the problem comes back.
What exactly is happening here? How do I get my defined avatarTM style to always take precedence, no matter what is loading the page or what the stylesheet is called? Why should the presence or absence of a file that is not being used by the app affect anything?
app2.js:
import React from 'react';
import { ThemeProvider } from '#material-ui/core/styles';
import { theme } from './components/Brand';
import TestComponent from './components/testComponent';
export default function App() {
return (
<React.Fragment>
<ThemeProvider theme={theme}>
<TestComponent />
</ThemeProvider>
</React.Fragment>
);
}
testComponent.js:
import React from 'react';
import Avatar from '#material-ui/core/Avatar';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import { useStyles } from './Brand';
export default function TestComponent() {
const classes = useStyles();
return (
<Card className={classes.card} variant="outlined">
<CardHeader
avatar={
<Avatar aria-label="testComponent" className={classes.avatarTM}>
t
</Avatar>
}
title="testComponent"
/>
</Card>
)}
brand.js:
import { createMuiTheme } from '#material-ui/core/styles';
import { makeStyles } from '#material-ui/core/styles';
const theme = createMuiTheme({
palette: {
primary: {
main: '#014EAA',
contrastText: '#ffffff',
},
secondary: {
main: '#0099CC',
contrastText: '#ffffff',
},
info: {
main: '#666666',
contrastText: '#ffffff',
},
error: {
main: '#FF6600',
contrastText: '#ffffff',
},
success: {
main: '#339933',
contrastText: '#ffffff',
},
},
});
// deleteme
const useStyles = makeStyles(theme => ({
root: {
color: theme.palette.primary,
fontSize: 10,
padding: '6px 12px',
fontFamily: ['sans-serif']
},
card: {
minwidth: 275,
},
title: {
fontSize: 24
},
cardTitle: {
fontSize: 24,
color: theme.palette.primary.main,
},
cardSubtitle: {
fontSize: 14,
color: theme.palette.secondary.main
},
cardDescription: {
fontSize: 10,
},
avatarTM: {
backgroundColor: theme.palette.primary.dark
},
avatarUnknown: {
backgroundColor: theme.palette.warning.main
},
avatarFixed: {
backgroundColor: theme.palette.primary.light
},
}));
export { theme, useStyles }
You can try force this style putting property like this:
avatarTM: {
backgroundColor: 'theme.palette.primary.dark !important'
},

How do I override checkbox color (box and font) in disabled state in material ui?

In Material UI v4.9.12 I can create a custom checkbox with a (fixed) different color:
const GreenCheckbox = withStyles({
root: {
color: green[400],
'&$checked': {
color: green[600],
},
},
checked: {},
})((props) => {
return <Checkbox {...props} />
}
)
But this doesn't change the font color and only sets the color when the checkbox isn't disabled.
How can I do both? What do I have to override?
So far I only managed to override the icon color with inline styling:
<GreenCheckbox style={{color: green[600]}} onChange={cb} checked={checked} disabled/>
You can override the default styles for the disabled state with the exact same approach you used for the checked state:
import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "#material-ui/core/styles";
import Checkbox from "#material-ui/core/Checkbox";
import green from "#material-ui/core/colors/green";
const GreenCheckbox = withStyles({
root: {
color: green[400],
"&$checked": {
color: green[600]
},
"&$disabled": {
color: green[200]
}
},
checked: {},
disabled: {}
})(Checkbox);
function App() {
return (
<div className="App">
<GreenCheckbox />
<GreenCheckbox disabled />
<GreenCheckbox checked disabled />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Related answers:
Change the tick color in MuiCheckbox material UI
Is there a way to create a ColoredCheckbox component?

Reddit text field implementation Material-UI

So I'm trying to immitate the reddit text field implementation from material-ui, I've gone ahead and setup this custom component, but I'm getting a invalid hook call error everytime I run on the const classes=... Line
Here's the code:
import React, { Component } from "react";
import { TextField } from "#material-ui/core";
import { fade, makeStyles } from "#material-ui/core/styles";
import styles from "./LNTextField.module.css";
const useStylesReddit = makeStyles(theme => ({
root: {
border: "1px solid #e2e2e1",
overflow: "hidden",
borderRadius: 4,
backgroundColor: "#fcfcfb",
transition: theme.transitions.create(["border-color", "box-shadow"]),
"&:hover": {
backgroundColor: "#fff"
},
"&$focused": {
backgroundColor: "#fff",
boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 2px`,
borderColor: theme.palette.primary.main
}
},
focused: {}
}));
class LNTextField extends Component {
render() {
var classNames = require("classnames");
const classes = useStylesReddit();
return (
<TextField
InputProps={{ classes, disableUnderline: true }}
{...this.props}
/>
);
}
}
export default LNTextField;
Also since I just copied it I'm not sure how I can type this code in a seperate css files and refer to the hover and focused bits appropriately, so If you could also tell me how to do that that'd be great. Thanks!
According to React, you are getting this error because:
You can’t use Hooks inside of a class component
Convert your class component to functional component:
const LNTextField = props => {
var classNames = require("classnames");
const classes = useStylesReddit();
return (
<TextField
InputProps={{ classes, disableUnderline: true }}
{...props}
/>
);
}

Changing styles during clicking

I have ReactJS project and I want to change colour of button during clicking. I know that it is a Ripple API but it's very incomprehensible to use it. Could someone advise me how can I do that?
I've tried to create two elements - parent and child - and changed background of child to transparent while clicking. Unfortunately I have also 'classes' object responsible for changing class if button is active and it is just not working.
My code below:
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import PropTypes from 'prop-types';
import styles from './MydButton.style';
class MyButton extends Component {
constructor(props) {
super(props);
this.state = {
isClicked: false
};
}
handleClick = () => {
this.setState({ isClicked: !this.state.isClicked });
}
render() {
const {
classes,
children,
color,
disabled,
className,
onClick,
type,
border,
...props
} = this.props;
const myClass = this.state.isClicked ? 'auxClass' : 'buttonDefaultRoot';
return (
<div className={classes.parentRoot} >
<Button
classes={{
root: disabled
? classes.buttonDisabledRoot
: classes.buttonRoot,
label: disabled
? classes.buttonLabelDisabled
: classes.buttonLabel,
}}
{...props}
onClick={this.handleClick}
className={myClass}
disabled={disabled}
type={type === undefined ? 'button' : type}
>
{children}
</Button>
</div>
)
}
};
MyButton.propTypes = {
children: PropTypes.string.isRequired,
disabled: PropTypes.bool,
classes: PropTypes.object.isRequired,
};
MyButton.defaultProps = {
disabled: false,
};
export default withStyles(styles)(MyButton);
and styles:
const buttonRoot = {
border: 0,
height: 48,
width: '100%',
}
export default theme => ({
buttonDefaultRoot: {
...buttonRoot,
transition: 'all 1s ease-in-out',
backgroundImage: 'linear-gradient(to right, #F59C81, #E65DA2, #E65DA2, #B13A97, #881E8E)',
boxShadow: '0px 1px 3px rgba(0, 0, 0, 0.16)',
backgroundSize: '300% 100%',
marginTop: 0,
'&:hover': {
backgroundPosition: '100% 0%',
transition: 'all 1s ease-in-out',
}
},
parentRoot: {
...buttonRoot,
backgroundColor: 'red',
backgroundSize: '300% 100%',
marginTop: 36,
},
auxClass: {
backgroundImage: 'none',
},
Material UI Core for ReactJS
The documentation is very good. I have updated my answer to accomodate the specific needs of this question. I have also included two general solutions for anyone who stumbles upon this question.
Tailored Solution:
Changes background color of button from classes.buttonDefaultRoot (a color defined by owner of question) to the gradient defined by the owner of this question.
First step, have a variable stored in state. You can call it whatever you want, but I'm calling bgButton. Set this to this.props.classes.buttonDefaultRoot like so:
state = {
bgButton: this.props.classes.buttonDefaultRoot,
}
Next, you want to define your function that will handle the click. Again, call it what you want. I will call it handleClick.
handleClick = () => {
const { classes } = this.props; //this grabs your css style theme
this.setState({ bgButton: classes.parentRoot.auxClass }); //accessing styles
};
A couple of things are happening here. First, I am destructuring props. So, I am creating a new const variable called classes that has the same value as this.props.classes. The classes contains a set of objects that defines your css styles for your buttons, margins, etc. You can access those styles just like you would if you were trying to get the value of a prop in an obj.
In this case you can access your button style by doing, classes.buttonDefaultRoot. That takes care of your handle click function.
Last step: render the button. In your render method you want to grab your bgButton from state like so:
render() {
const { bgButton } = this.state;
Then you want to assign your className of your button to bgButton and add the onClick functionality like this (this follows the Material UI Core documentation):
<Button variant="contained" color="primary" className={classNames(bgButton)} onClick={this.handleClick}>Button Name</Button>
Putting it all together you get this:
import React, { Component } from "react";
import Button from "#material-ui/core/Button";
import PropTypes from "prop-types";
import classNames from "classnames";
import { withStyles } from "#material-ui/core/styles";
export default theme => ({ ... }) //not going to copy all of this
class MyButton extends Component {
state = {
bgButton: null
};
handleClick = () => {
const { classes } = this.props;
this.setState({ bgButton: classes.parentRoot.auxClass });
};
render() {
const { bgButton } = this.state;
return (
<div className={classes.container}>
<Button
variant="contained"
color="primary"
className={classNames(bgButton)}
onClick={this.handleClick}
>
Custom CSS
</Button>
</div>
);
}
}
MyButton.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(MyButton);
General Solution
This solution is for those who want to use the predefined colors, i.e. default, primary, secondary, inherit. This implementation does not need the PropTypes or className imports. This will change the color from the predefined blue to the predefined pink. That's it.
state = {
bgButton: "primary",
}
handleClick = () => {
this.setState({ bgButton: "secondary" });
}
render() {
const { bgButton } = this.state;
return(
...
<Button
onClick = {this.handleClick}
variant = "contained" //checked Material UI documentation
color={bgButton}
> ..etc.
General Solution 2
To accommodate your custom styles to the button, you would have to import PropTypes and classNames and take a similar approach as the tailored solution above. The only difference here will be my syntax and class name. I am closely following the documentation here so you can easily follow along and readjust where necessary.
import React, { Component } from "react";
import Button from "#material-ui/core/Button";
import PropTypes from "prop-types";
import classNames from "classnames";
import { withStyles } from "#material-ui/core/styles";
import purple from "#material-ui/core/colors/purple";
const styles = theme => ({
container: {
display: "flex",
flexWrap: "wrap"
},
margin: {
margin: theme.spacing.unit
},
cssRoot: {
color: theme.palette.getContrastText(purple[500]),
backgroundColor: purple[500],
"&:hover": {
backgroundColor: purple[700]
}
},
bootstrapRoot: {
boxShadow: "none",
textTransform: "none",
fontSize: 16,
padding: "6px 12px",
border: "1px solid",
backgroundColor: "#007bff",
borderColor: "#007bff",
fontFamily: [
"-apple-system",
"BlinkMacSystemFont",
'"Segoe UI"',
"Roboto",
'"Helvetica Neue"',
"Arial",
"sans-serif",
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"'
].join(","),
"&:hover": {
backgroundColor: "#0069d9",
borderColor: "#0062cc"
},
"&:active": {
boxShadow: "none",
backgroundColor: "#0062cc",
borderColor: "#005cbf"
},
"&:focus": {
boxShadow: "0 0 0 0.2rem rgba(0,123,255,.5)"
}
}
});
class MyButton extends Component {
state = {
bgButton: null
};
handleClick = () => {
const { classes } = this.props;
this.setState({ bgButton: classes.cssRoot });
};
render() {
const { classes } = this.props; //this gives you access to all styles defined above, so in your className prop for your HTML tags you can put classes.container, classes.margin, classes.cssRoot, or classes.bootstrapRoot in this example.
const { bgButton } = this.state;
return (
<div className={classes.container}>
<Button
variant="contained"
color="primary"
className={classNames(bgButton)}
onClick={this.handleClick}
>
Custom CSS
</Button>
</div>
);
}
}
MyButton.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(MyButton);
A tip. You no longer need a constructor or to bind methods.
Hope this helps.

Resources