I have some components that use the MuiThemeProvider to customize a button. The reason is probably because you can only have "primary" or "secondary" instead of a custom palette name. They look like this:
import React from "react";
import { badTheme } from "./Themes";
import {
Button,
MuiThemeProvider,
} from "#material-ui/core";
class Widget extends React.Component {
render() {
return (
<MuiThemeProvider theme={badTheme}>
<Button color="primary">Click me</Button>
</MuiThemeProvider>
);
}
}
export default Widget;
The badTheme here is just the app theme with an override for main in the primary palette.
const badTheme= createMuiTheme({
...defaultTheme,
palette: {
...defaultTheme.palette,
primary: {
main: "#2B368B",
},
},
});
It would be nice to get rid of these little themes that just change a button, so I want to know what are all the styles I need to implement when switching to withStyles.
I don't want to lose the ripple style or any other style I'm not aware of that is seeded from setting main in the palette.
What does it take to replace MuiThemeProvider with withStyles, or whatever else, and having the exact same styles on this button that are seeded based on the main palette setting?
Each Button variant has its own color styles, which are defined in Button.js.
To create new button colors using withStyles (instead of the color prop), you will need to replicate the color-specific styles for the desired variant.
As of material-ui#3.1.1, these are the styles to create a custom button color for each variant.
Text buttons
Color styles for the default button variant. Based on .textPrimary
Note: These styles are also applied to the outlined variant.
textPink: {
color: pink[500],
"&:hover": {
backgroundColor: fade(pink[500], theme.palette.action.hoverOpacity),
// Reset on touch devices, it doesn't add specificity
"#media (hover: none)": {
backgroundColor: "transparent"
}
}
},
Outlined buttons
Color styles for outlined button variant. Based on .outlinedPrimary
outlinedPink: {
border: `1px solid ${fade(pink[500], 0.5)}`,
"&:hover": {
border: `1px solid ${pink[500]}`
},
"&$disabled": {
border: `1px solid ${theme.palette.action.disabled}`
}
},
Contained Buttons
Color styles for contained/raised button variant. Based on .containedPrimary
containedPink: {
color: theme.palette.getContrastText(pink[500]),
backgroundColor: pink[500],
"&:hover": {
backgroundColor: pink[700],
// Reset on touch devices, it doesn't add specificity
"#media (hover: none)": {
backgroundColor: pink[500]
}
}
}
Complete Example:
Related
I am new to material ui.
I use fifth version.
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
sx={{
...InputCSS,
}}
/>
const InputCSS = {
width: '100%',
textIndent: '17px',
py: '12px',
fontSize: '20px',
borderRadius: '3px',
border: '1.5px solid rgba(0, 0, 0, 0.4)',
'MuiInputBase-root': { // does not work
borderColor: 'red !important',
color: 'red !important',
},
'&:focus' : { // does not work
...
}
}
I could have used styled('input') and it works, I can set &:focus and it works but I can't type anything in the input.
I want to get rid of the initial border and set focus property.
How can I change the border for this class?
I know that in v5 we can style our components using variants or sx or styled.
What is the best advice for styling mui components? Because almost all the info in the internet uses outdated useStyle or makeStyles which doesn't work with react 18v.
sometimes I just struggle with components styling in mui
You have several ways to customize a Mui component, but my three favorite approaches are:
Styled utility
Sx prop
Custom global theme
So when should I use each of these approaches?
Styled utility
If you want to make a component reusable across your app, go with styled, if you had ever used styled components then styled will be very familiar to you, here is an example of how to use it:
import * as React from 'react';
import Slider, { SliderProps } from '#mui/material/Slider';
import { alpha, styled } from '#mui/material/styles';
// if you are using typescript, don't forget to pass the component props on styled
const SuccessSlider = styled(Slider)<SliderProps>(({ theme }) => ({
width: 300,
color: theme.palette.success.main,
// to override the styles of inner elements,
// you have to use the & selector followed by the class name.
'&.MuiSlider-thumb': {
'&:hover, &.Mui-focusVisible': {
boxShadow: `0px 0px 0px 8px ${alpha(theme.palette.success.main, 0.16)}`,
},
'&.Mui-active': {
boxShadow: `0px 0px 0px 14px ${alpha(theme.palette.success.main, 0.16)}`,
},
},
}));
export default function StyledCustomization() {
return <SuccessSlider defaultValue={30} />;
}
To make the component even more dynamically, you can define custom props as well, like width, color, border and so on, read the styled docs to know more about it.
Sx prop
If you want to make an one time off style in a single component, the easiest way is to use the sx prop, but be careful with this approach because it can lead to a lot of repetition in your code. Following the code you gave:
<InputBase
ref={params.InputProps.ref}
inputProps={params.inputProps}
autoFocus
sx={{
...InputCSS,
}}
/>
const InputCSS = {
width: '100%',
textIndent: '17px',
py: '12px',
fontSize: '20px',
borderRadius: '3px',
border: '1.5px solid rgba(0, 0, 0, 0.4)',
// you should pass the & selector followed by the class that you want to override
'&.MuiInputBase-root': {
// avoid the use of !important
borderColor: 'red',
color: 'red',
},
'&.MuiInputBase-root:focus': {
...
}
}
check it out on codeSandbox. Just a suggestion, depending on your case the component TextField could fit better as it comes with some good styles and you don't need to style it from scratch.
Side note:
Every mui component has an api doc with a css section where you can find all available classes to override, for instance, see the InputBase api docs, also read the docs about sx prop.
Custom theme
At last but not least, if you want to customize your whole app with custom palette, components, typography, breakpoints and so on, no doubt you should use a custom theme, as mui provides a powerful tool called createTheme to do so, what I like the most in custom theme is the possibility to make custom variants of the component, like so:
import * as React from "react";
import { createTheme, ThemeProvider } from "#mui/material/styles";
import Button from "#mui/material/Button";
import { red } from "#mui/material/colors";
// if you are using typescript, you must declare the module with the
// custom properties in order to get access of this property when using the component
declare module "#mui/material/Button" {
// define custom variants
interface ButtonPropsVariantOverrides {
dashed: true;
redVariant: true;
}
}
const defaultTheme = createTheme();
const theme = createTheme({
components: {
MuiButton: {
variants: [
{
// use the variant name defined earlier
props: { variant: "dashed" },
// set the styles for this variant
style: {
textTransform: "none",
border: `2px dashed ${defaultTheme.palette.primary.main}`,
color: defaultTheme.palette.primary.main
}
},
{
props: { variant: "redVariant" },
style: {
border: `2px solid ${red[300]}`,
color: red[600]
}
}
]
}
}
});
export default function GlobalThemeVariants() {
return (
// use the theme provider to get access of custom theme
// and variants within any child component
<ThemeProvider theme={theme}>
<Button variant="dashed" sx={{ m: 1 }}>
Dashed
</Button>
<Button variant="redVariant" color="secondary">
custom red variant
</Button>
</ThemeProvider>
);
}
See the example, also take a look at the custom theme docs. Hope I clarified the things a bit!
i want to change the color of typography by hovering on card . after trying alot finaly i decided to post here. if i remove the color from typography and then hover on card then it works, it change the color of text by hover on card. but i dont want default typography color i want to use one of mine. check screen shots please.enter image description here
enter image description here
enter image description here
enter image description here
enter image description here
To change a style of a child when hovering over a parent using React Material UI styles, we can call makeStyles with the &:hover selector of the parent element to change the styles when we hover over the child element.
for example :- here outerdiv is perent element and addIcon is child element
import * as React from "react";
import { Grid, makeStyles } from "#material-ui/core";
import AddIcon from "#material-ui/icons/Add";
const useStyles = makeStyles((theme) => ({
outerDiv: {
backgroundColor: theme.palette.grey[200],
padding: theme.spacing(4),
"&:hover": {
cursor: "pointer",
backgroundColor: theme.palette.grey[100],
"& $addIcon": {
color: "purple"
}
}
},
addIcon: () => ({
height: 50,
width: 50,
color: theme.palette.grey[400],
marginBottom: theme.spacing(2)
})
}));
export default function App() {
const classes = useStyles();
return (
<Grid container>
<Grid item className={classes.outerDiv}>
<AddIcon className={classes.addIcon} />
</Grid>
</Grid>
);
}
because you set color in attribute, and if u set color in color attribute, your hover not working.
<Typography
variant="body2"
color={theme.palette.primary.dark}
</Typography>
if you want set hover for this, you have to set default color and hover in makeStyles() or styled().
like this one, i make for myself:
import { styled } from '#mui/material/styles';
import MuiListItemButton from '#mui/material/ListItemButton';
const ListItemButton = styled(MuiListItemButton)(({ theme }) => ({
color: theme.palette.primary.main,
'& svg': { color: theme.palette.primary.main },
'&:hover, &:focus': {
color: theme.palette.white.main,
backgroundColor: theme.palette.primary.main,
'& svg': { color: theme.palette.white.main },
},
}));
I'm not very deep into React yet...
The AppBar is styled like a button which i don't like.
So I want to change it's colors but also have it working switching light and dark scheme.
[Edit]
I want to define own colors for AppBar (without changing present colors) und add them to light/dark theme respectively so it's changing automatically to light/dark when i switch themes.
[/Edit]
Changing colors with ThemeProvider is already not working:
const theme = createMuiTheme({
palette: {
// type: 'dark'
},
overrides: {
MuiTypography: {
h1: {
fontSize: 24,
fontWeight: "normal"
},
h2: {
fontSize: 22,
fontWeight: "normal"
},
},
MuiAppBar: {
background: 'white',
borderBottom: "1px solid lightGray",
}
},
MuiTypography works, though.
(As I see here https://material-ui.com/customization/default-theme/ there's no AppBar only Typography.)
How can I tell AppBar to use other colors than primary/secondary while staying synced with the built-in light-dark-theme mechanic?
Ciao, if you want to switch theme (from dark theme to light theme for example) you could use primary and secondary colors (previously defined in theme object).
So lets take this codesandbox example I made:
I defined 2 colors in theme:
const Theme = {
palette: {
primary: {
main: "#000000"
},
secondary: {
main: "#FFFFFF"
}
}
};
In this case, primary is our dark theme and secondary is the light theme.
I created MUI theme:
const theme = createMuiTheme(Theme);
I wrapped the AppBar component into a ThemeProvider with the theme created:
<ThemeProvider theme={theme}>
<AppBar position="static" color={themeSelected}>
....
</AppBar>
</ThemeProvider>
As you can see on AppBar component, I putted a state variable in color props (themeSelected).
Well now I created just a simple IconButton with an SwapHoriz icon , and on click I change my state variable themeSelected:
...
const [themeSelected, setThemeSelected] = useState("primary"); // init as primary color
...
const changeTheme = () => { // function to set state
if (themeSelected === "primary") setThemeSelected("secondary");
else setThemeSelected("primary");
};
...
<IconButton //icon button with onClick handler
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
onClick={() => {
changeTheme();
}}
>
<SwapHoriz />
</IconButton>
Thats it. Now if you click SwapHoriz you can change your color theme:
Primary color theme
Secondary color theme
EDIT
After you explanation, I understood that you want distinct colors for AppBar and, when you change theme, AppBar should take that colors.
In this case the only way I know is to override the classes of AppBar in this way:
<AppBar
position="static"
color={themeSelected}
classes={{
colorPrimary: classes.appbarpalette,
colorSecondary: classes.appbarpalette
}}
>
Then in your makeStyles:
...
appbarpalette: {
"&.MuiAppBar-colorPrimary": {
backgroundColor: purple[600] // instead of #000000 for primary now you have purple
},
"&.MuiAppBar-colorSecondary": {
backgroundColor: green[600] // instead of #FFFFFF for secondary now you have green
}
}
I updated my codesandbox example.
I'm building an app with the Material-UI library for ReactJS. Using the Theme Overrides API, I'm trying to figure out how I can globally style a component, but only when it is a child of another specific component.
For example, I'm trying to set the background/text coloring of MenuItems inside a <Select> menu, where each <MenuItem> contains a <listItemText>. Here's my component:
import { MenuItem, Select, ListItemText } from '#material-ui/core';
import { MuiThemeProvider } from '#material-ui/core/styles';
import * as React from 'react';
import theme from './theme';
const MySelect = props => {
return (
<MuiThemeProvider theme={theme}>
<Select variant="standard" value="2" open>
<MenuItem value="1">
<ListItemText>One</ListItemText>
</MenuItem>
<MenuItem value="2">
<ListItemText>Two</ListItemText>
</MenuItem>
<MenuItem value="3">
<ListItemText>Three</ListItemText>
</MenuItem>
<MenuItem value="4">
<ListItemText>Four</ListItemText>
</MenuItem>
</Select>
</MuiThemeProvider>
);
};
export default MySelect;
Unfortunately, applying a color to the <MenuItem> directly doesn't work because the <ListItemText> overrides it with a <Typography> that has its own coloring set. This is fine for a non-hovered, non-selected state, but if I style the "selected" MenuItem to have a darker background, I need it to have a lighter text.
Here is my theme file:
import { createMuiTheme, createStyles } from '#material-ui/core';
const myTheme = createMuiTheme({
overrides: {
MuiMenuItem: createStyles({
root: {
'&&:hover': {
backgroundColor: 'pink',
color: 'white'
}
},
selected: {
'&&': {
backgroundColor: 'blue',
color: 'white'
},
'&&:hover': {
backgroundColor: 'darkblue',
color: 'white'
}
}
}),
// How do I enforce this ONLY inside of MuiMenuItem and only for
// the selected variant of that?
MuiTypography: {
subheading: {
color: 'white'
}
}
}
});
export default myTheme;
So, my question is: is there a way to do this using just Theme Overrides? Or do I need to conditionally pass this styling into the <ListItemText> component using props? Since most of the styling here fits nicely into Theme Overrides, that seems like a nicer way to do it, but maybe I'm misusing the API.
For a working demo of my above code, see: https://codesandbox.io/s/3r9mkxq231
Any insight is welcome! Thank you!
One way to accomplish that is to target the descendant html element (e.g. the span for the ListItemText) from the ancestor styles (MenuItem in this case).
Here's an example of how the MenuItem.selected style could be specified:
selected: {
"&&": {
backgroundColor: "blue",
color: "white",
"&& span": {
color: "white"
}
},
"&&:hover": {
backgroundColor: "darkblue",
color: "white"
}
}
The full code (forked from your CodeSandbox) is here:
First of all, I don't think we can do that in the theme overrides. Theme overrides is a way to override a default style configuration of an existing material-ui component.
Second, I don't think you need to make it too complex with conditional statements. This can be solved without that also. I didn't understand why did you need to use <ListItemText> when <MenuItem> itself has functionality to display text.
Just simply remove <ListItemText> from you code and then you can use theme overrides to modify your <MenuItem> as you like.
Find the modified code here : https://codesandbox.io/s/30p3o4jjz5
Let me know if this clarifies your doubt.
Yes you can do this in theme overrides using jss-nested syntax:
const myTheme = createMuiTheme({
overrides: {
MuiMenuItem: createStyles({
root: {
"&&:hover": {
backgroundColor: "pink",
"& *": {
color: "white"
}
}
},
selected: {
"&&": {
backgroundColor: "blue",
"& *": {
color: "white"
}
},
"&&:hover": {
backgroundColor: "darkblue",
"& *": {
color: "white"
}
}
}
})
}
});
export default myTheme;
See working codepen here: https://codesandbox.io/embed/308mk7k5x6?fontsize=14
I am trying to use my custom color for AppBar header. The AppBar has title 'My AppBar'. I am using white as my primary theme color. It works well for the bar but the 'title' of the AppBar is also using same 'white' color'
Here is my code:
import React from 'react';
import * as Colors from 'material-ui/styles/colors';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import AppBar from 'material-ui/AppBar';
import TextField from 'material-ui/TextField';
const muiTheme = getMuiTheme({
palette: {
textColor: Colors.darkBlack,
primary1Color: Colors.white,
primary2Color: Colors.indigo700,
accent1Color: Colors.redA200,
pickerHeaderColor: Colors.darkBlack,
},
appBar: {
height: 60,
},
});
class Main extends React.Component {
render() {
// MuiThemeProvider takes the theme as a property and passed it down the hierarchy
// using React's context feature.
return (
<MuiThemeProvider muiTheme={muiTheme}>
<AppBar title="My AppBar">
<div>
< TextField hintText = "username" / >
< TextField hintText = "password" / >
</div>
</AppBar>
</MuiThemeProvider>
);
}
}
export default Main;
But, the palette styles override the AppBar 'title' color and no title is displaying. Should I include something or I have misplaced any ?
And this is my output :
If you ant to change your Appbar background in material ui design ....try following code
<AppBar style={{ background: '#2E3B55' }}>
or if you want to apply className then follow this step
first of all make create const var
const style = {
background : '#2E3B55';
};
<AppBar className={style}>
MUI v5 update
1. Use sx prop
<AppBar sx={{ bgcolor: "green" }}>
2. Set primary.main color in Palette
The Appbar background color uses the primary color provided from the theme by default.
const theme = createTheme({
palette: {
primary: {
main: "#00ff00"
}
}
});
3. Set AppBar default styles in styleOverrides
Use this one if you don't want to touch the primary.main value and potentially affect other components:
const theme = createTheme({
components: {
MuiAppBar: {
styleOverrides: {
colorPrimary: {
backgroundColor: "red"
}
}
}
}
});
From what I see in the material-ui sources, appBar title color is set by palette.alternateTextColor. If you add it to your style definition like that:
const muiTheme = getMuiTheme({
palette: {
textColor: Colors.darkBlack,
primary1Color: Colors.white,
primary2Color: Colors.indigo700,
accent1Color: Colors.redA200,
pickerHeaderColor: Colors.darkBlack,
alternateTextColor: Colors.redA200
},
appBar: {
height: 60,
},
});
You should see your title without need to style it manually inside each component.
There are more styling parameters to MuiTheme described here
Create your style using makeStyles():
const useStyles = makeStyles(theme => ({
root: {
boxShadow: "none",
backgroundColor: "#cccccc"
}
}));
Use the above style in your component:
const classes = useStyles();
<AppBar className={classes.root} />
Please make theme.js first.
- theme.js
import { red } from '#material-ui/core/colors';
import { createMuiTheme } from '#material-ui/core/styles';
export default createMuiTheme({
palette: {
primary: {
main: '#556cd6',
},
secondary: {
main: '#19857b',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
});
Add these lines to index.js
import { ThemeProvider } from '#material-ui/core/styles'
import theme from './theme'
ReactDOM.render(
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>,
document.getElementById('root')
);
<AppBar position='static' color='secondary' elevation={2}>
...
</AppBar>
*** important ***
secondary: {
main: '#19857b',
},
color='secondary'
Finally, I came to know about titleStyle for styling title in AppBar.
const titleStyles = {
title: {
cursor: 'pointer'
},
color:{
color: Colors.redA200
}
};
<AppBar title={<span style={titleStyles.title}>Title</span>} titleStyle={titleStyles.color}> .............
</AppBar>
By default it uses palette's contrastText prop (v3):
const theme = createMuiTheme({
palette: {
primary: {
contrastText: 'rgba(0,0,0,0.8)'
}
},
});
first of all, add const to the file. Then apply to the line u need as following shown.
const styles = { button: { margin: 15,}, appBarBackground:{ background : '#2E3B55' }};
Then add it to the line as shown down
style={styles.button}
style={styles.appBarBackground}
You cat add this inline your code
<AppBar title="My AppBar" style={{ backgroundColor: '#2196F3' }} >
or if your css
import './home.css';
put this to your code
.title {
text-align: left;
background-color: black !important;}
Hope to help.
Working on #NearHuscarl answer. If you want the styles to be applied no matter which appbar color you are on: E.g. <Appbar color="secondary" or <Appbar color="primary". You could alternatively use the root property:
const theme = createTheme({
components: {
MuiAppBar: {
root: {
colorPrimary: {
backgroundColor: "red"
}
}
}
}
});
The difference is the root keyword
You can set the background color directly using sx property
<AppBar variant='elevated' sx={{backgroundColor:'#19857b'}}>