React MaterialUI Theming | How to increase transition duration when switching theme? - reactjs

I am making a light/dark theme using React MaterialUi.
Question: Is there any possibility to ease theme transition speed instead of instant transition ?
Problem:
I've already tried inline styling with style={{transition: "all 1s linear}} in the parent div but it only works on text color and not the background color (still switches instantly)
I also tried to override transitions duration in createMuiTheme({transitions: {/ /}}) but it has no effect

SOLVED
If you are using CssBaseline to reset global styling, you can also define new rules inside createMuiTheme({}) to define a global body {transition: "all
0.5s linear"}.
Global Css reset with CssBaseline
export default function Layout({ children }) {
const {
state: { darkMode },
} = useContext(AppContext);
const theme = darkTheme(darkMode);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<div
style={{
minHeight: '100vh',
boxSizing: 'border-box',
}}>
<Navbar />
{children}
</div>
</ThemeProvider>
);
}
New Global css "overrides" inside createMuiTheme()
export const darkTheme = (dark: boolean): ThemeOptions => {
const paletteColors = dark ? paletteColorsDark : paletteColorsLight;
return createMuiTheme({
palette: {
type: dark ? 'dark' : 'light',
primary: {
main: paletteColors.primary,
},
secondary: {
main: paletteColors.secondary,
},
/////// IMPORTANT PART //////////////////////////////////////////
},
overrides: {
MuiCssBaseline: {
'#global': {
body: {
transition: 'all 0.3s linear',
},
},
},
},
});
};
NB: you may need some extra inline styling for specific elements (AppBar in my case)
<AppBar
position='static'
color='default'
elevation={1}
style={{ transition: 'all 0.3s linear' }}>
{/* */}
</AppBar>

body {
transition: all 0.25s ease-in-out;
}
Add this to your top-level CSS import. This might be an index.css and then import "./index.css"; is in the main.jsx (or wherever you have stuff like: <React.StrictMode>).
I see this was covered in the comments in the original question.

Related

how to apply global backgroundColor using MuiCssBaseline and styleOverrides

I want to add global backgroundColor for the app where we use ThemeProvider. I see strange situation which I cannot figure out. Below in the picture You can see that body component don't "catch" whole components for the app, also please look at body props in devtools, backgroundColor and color (added for test) are different than I have added to the code below.Component with text:"Wybierz koło..." is rendered conditionally, that's why I want to make backgroundColor property globally to cover such situations.
This is how MainTheme is built :
components: {
MuiCssBaseline: {
styleOverrides: {
'#global': {
html: {
fontSize: '62.5%' /* 62.5% of 16px = 10px */,
fontFamily: 'Poppins, sans-serif',
},
body: {
margin: '0',
color: 'red',
boxSizing: 'border-box',
fontFamily: 'Poppins, sans-serif',
backgroundColor: '#E3E3E3',
},
},
},
},
Here You can see how App component is biuld
export const App: FC = () => (
<StyledEngineProvider injectFirst>
<ThemeProvider theme={MainTheme}>
<SCThemeProvider theme={MainTheme}>
<CssBaseline />
<Router>
<AuthContextProvider>
<Notifications />
<RoutingManager />
</AuthContextProvider>
</Router>
</SCThemeProvider>
</ThemeProvider>
</StyledEngineProvider>
);
This conditional component is rendered based on displayTooltipText
<StyledTable {...getTableProps()}>
{displayTooltipText ? (
<tbody>
<StyledTextWrapper>
{selectWheelText}
</StyledTextWrapper>
</tbody>
) : (
<TableBody
getTableBodyProps={getTableBodyProps}
prepareRow={prepareRow}
rows={rows}
/>
)}
</StyledTable>
thanks a lot !
You need to remove the '#global': { wrapper layer. You can see here how the default styles are defined and overrides need to be defined in the same way. Those styles (the defaults plus your overrides), then get passed to the GlobalStyles component which handles the global scoping.
Here's a working example:
import * as React from "react";
import CssBaseline from "#mui/material/CssBaseline";
import { createTheme, ThemeProvider } from "#mui/material/styles";
const theme = createTheme({
components: {
MuiCssBaseline: {
styleOverrides: {
html: {
fontSize: "62.5%" /* 62.5% of 16px = 10px */,
fontFamily: "Poppins, sans-serif"
},
body: {
margin: "0",
color: "red",
boxSizing: "border-box",
fontFamily: "Poppins, sans-serif",
backgroundColor: "#E3E3E3"
}
}
}
}
});
export default function Demo() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<div>Hello World</div>
</ThemeProvider>
);
}

MUI Theme hook version 5 : creating global theme

I'm trying to create a theme for my Next.JS application with MUI version 5. I created the Theme in my layout component, and I expected the Theme to have effect in other child components. but I can't seem to get my Button to change from the default primary colour. It does work with the "h1"tag, and I'm wondering why it works for the h1 tag and not for the Button component.
//layout component
import { AppBar, Container, CssBaseline, Toolbar, Typography ,createTheme, ThemeProvider} from '#mui/material';
import useStyles from '../utils/styles';
export default function Layout({ title, children, description }) {
const theme = createTheme({
typography: {
h1: {
fontSize: '1.6rem',
fontWeight: 400,
margin: '1rem 0', // this is working
},
h2: {
fontSize: '1.4rem',
fontWeight: 400, // this is working
margin: '1rem 0',
},
palette: {
type: 'light',
primary: { // this is not working
main: '#f0c000',
},
secondary: {
main: '#208080',
},
},
},
});
const classes = useStyles()
return (
<div>
<ThemeProvider theme={theme}>
<CssBaseline/>
<AppBar position="static" className={classes.navbar}>
<Toolbar>
<Typography>App</Typography>
</Toolbar>
</AppBar>
<Container className={classes.main}>{children}</Container>
<footer className={classes.footer}>
<Typography>All right reserved</Typography>
</footer>
</ThemeProvider>
</div>
);
}
Component where I want to use the Theme :
import useStyles from '../../utils/styles'
import { useTheme } from '#mui/material';
export default function ButtonScreen() {
const theme = useTheme();
const classes = useStyles();
return (
// this h1 tag responds to the Theme style provided in the layout component
<Typography component="h1" variant="h1">
Button Action
</Typography>
//The button default colour still persist, even with the theme in place.
<Button fullWidth variant='contained' color="primary">Click me</Button>
)
}
Can someone help me figure out what I am missing here?!

How to keep the background color of disabled Button in Material-UI?

I want to change the global style of the disabled Button component from Material-UI. But the problem is I am unable to keep the original color scheme of the button.
Consider this button:
<Button color="secondary" disabled={isLoading}>Create Account</Button>
Now by default Mui-disabled would be attached to this button. Whose color and the background-color are taken from theme.palatte.action property. So this disabled button would be having CSS as:
color: rgba(0,0,0,0.26);
box-shadow: none;
background-color: rgba(0,0,0,0.12);
But I want my disabled button to maintain its original color ("primary, secondary", "error" etc.) added with an opacity of 0.7. By default, the cursor events are set to none by MUI.
I tried it using the custom theme but I don't know how to maintain the original color of the button. E.g if the Button is primary keep the primary color, if the Button is secondary keep the secondary colors.
MuiButton: {
styleOverrides: {
root: {
textTransform: "none",
boxShadow: "none",
"&.Mui-disabled": {
// background: "initial",
// color: "initial",
opacity: .7
}
},
}
}
Of course, I don't want to write a custom code for each code. I can do this even by creating a wrapper around the MUI's button and use that wrapper everywhere in my code.
But I want to do it the MUI way by overriding the theme.
How can I implement a global solution?
Is this what you want? just don't set the disabledBackground color in the palette:
import Button, { buttonClasses } from "#mui/material/Button";
import { createTheme, ThemeProvider } from "#mui/material/styles";
const defaultTheme = createTheme();
const theme = createTheme({
palette: {
action: {
disabledBackground: "", // don't set the disable background color
disabled: "white", // set the disable foreground color
}
},
components: {
MuiButtonBase: {
styleOverrides: {
root: {
[`&.${buttonClasses.disabled}`]: {
opacity: 0.5
},
// Fix ButtonGroup disabled styles.
[`&.${toggleButtonClasses.root}.${buttonClasses.disabled}`]: {
color: defaultTheme.palette.action.disabled,
borderColor: defaultTheme.palette.action.disabledBackground
}
}
}
}
}
);
At the current time I'm writing. There is also other components that reuses the disableBackground property, make sure you take a look and are okay with that too. I display them all in the example below.
Live Demo
With the way that the disabled state is handled in the default styles, I think you need to redefine the default colors within your override in order for it to work.
In the source code you can find how the default colors are defined for the text, outlined, and contained variants.
The example below demonstrates overriding the disabled styles for all three variants with opacity: 0.7 by redefining the non-disabled colors within the "&.Mui-disabled" style overrides.
import * as React from "react";
import Stack from "#mui/material/Stack";
import Button from "#mui/material/Button";
import { createTheme, ThemeProvider } from "#mui/material/styles";
import { alpha } from "#mui/system";
const defaultTheme = createTheme();
const colors = [
"inherit",
"primary",
"secondary",
"success",
"error",
"info",
"warning"
];
const containedColorStyles = {};
const textColorStyles = {};
const outlinedColorStyles = {};
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
colors.forEach((color) => {
containedColorStyles[`&.MuiButton-contained${capitalizeFirstLetter(color)}`] =
color === "inherit"
? {
backgroundColor: defaultTheme.palette.grey[300],
color: defaultTheme.palette.getContrastText(
defaultTheme.palette.grey[300]
)
}
: {
backgroundColor: defaultTheme.palette[color].main,
color: defaultTheme.palette[color].contrastText
};
textColorStyles[`&.MuiButton-text${capitalizeFirstLetter(color)}`] =
color === "inherit"
? {
color: "inherit"
}
: {
color: defaultTheme.palette[color].main
};
outlinedColorStyles[`&.MuiButton-outlined${capitalizeFirstLetter(color)}`] =
color === "inherit"
? {
color: "inherit",
borderColor:
defaultTheme.palette.mode === "light"
? "rgba(0, 0, 0, 0.23)"
: "rgba(255, 255, 255, 0.23)"
}
: {
color: defaultTheme.palette[color].main,
borderColor: `${alpha(defaultTheme.palette[color].main, 0.5)}`
};
});
const theme = createTheme({
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: "none",
boxShadow: "none",
"&.Mui-disabled": {
...containedColorStyles,
...textColorStyles,
...outlinedColorStyles,
opacity: 0.7
}
}
}
}
}
});
export default function ColorButtons() {
const variants = ["text", "outlined", "contained"];
return (
<ThemeProvider theme={theme}>
{variants.map((variant) => (
<div key={variant}>
{capitalizeFirstLetter(variant)} Variant
<Stack direction="row" spacing={2}>
{colors.map((color) => (
<Button key={color} variant={variant} color={color}>
{capitalizeFirstLetter(color)}
</Button>
))}
</Stack>
Disabled {capitalizeFirstLetter(variant)} Variant
<Stack direction="row" spacing={2} sx={{ mb: 2 }}>
{colors.map((color) => (
<Button key={color} disabled variant={variant} color={color}>
{capitalizeFirstLetter(color)}
</Button>
))}
</Stack>
</div>
))}
</ThemeProvider>
);
}
I have a nice solution for now.
I use the ownerState props to get the color props. Next, I use it in the theme's palette. The following example illustrates how to do this for a contained button.
let theme = createTheme({
palette: {
// Your custom palette
},
});
theme = createTheme(theme, {
components: {
MuiButton: {
defaultProps: {
disableElevation: true
},
styleOverrides: {
root: ({ ownerState }) => ({
'&.MuiButton-contained.Mui-disabled': {
backgroundColor: theme.palette[ownerState.color].main,
}
}),
}
}
}
});

Material-UI React: Global theme override for Paper component

I have a React app built with the latest Material-UI component library.
I use many instances of the Paper component. I want to apply margins and padding to all them at once, without manually repeating this process for every instance.
I looked up the Material-UI documentation on the topic, and from what I can tell, the following code should correctly override how Paper looks:
const theme = createMuiTheme({
overrides: {
Paper: {
root: {
padding: '10px',
marginBottom: '10px',
},
},
},
});
Below is where overridden style should apply:
<ThemeProvider theme={theme}>
{/* ... */}
<Paper>
Content goes here
</Paper>
{/* ... */}
</ThemeProvider>
But the overridden values aren't being applied. Any suggestions as to what's going on?
Thanks!
in your App.js add (please note MuiPaper and not Paper):
const theme = createMuiTheme({
overrides: {
MuiPaper: {
root: {
padding: '10px',
marginBottom: '10px'
},
},
}
});
at the same App.js file, wrap your HTML:
class App extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<div className="App">
<YourComponent1 />
<YourComponent2 />
...
</div>
</MuiThemeProvider>
);
}
}
this way, any Paper component rendered by React will have your CSS.
BTW, I created MUI schematics module which adds Material UI support, generates several Material UI components automatically and adds general theme rules in App.js. You are welcome to take a look / try it...
You can also use your CssBaseline component if you're already using it for global reset...all depends on how you're structuring your theme.
Eg below is from the Mui docs:
<CssBaseline.js>
const theme = createMuiTheme({
overrides: {
MuiCssBaseline: {
'#global': {
html: {
WebkitFontSmoothing: 'auto',
},
},
},
},
});
// ...
return (
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
);
You can get more details from the docs here using CssBaseline to inject global theme overrides.
I found out the problem.
The internal component name used for CSS is MuiPaper, not simply Paper. The following produces the desired result:
overrides: {
MuiPaper: {
root: {
padding: '10px',
marginBottom: '10px',
},
},
},
createMuiTheme is depreciated in MUI5.
Instead, you should be using createTheme as follows:
export const myTheme = createTheme({
components:{
MuiPaper:{
defaultProps:{
sx:{
padding: '10px',
marginBottom: '10px'
}
}
}
}
})
Additionally, make sure that you wrap your app in the Theme component and add the CssBaseline component:
import { ThemeProvider } from '#mui/material';
import { myTheme } from './themes/my-theme';
import CssBaseline from '#mui/material/CssBaseline';
<ThemeProvider theme={myTheme}>
<CssBaseline />
<MyApp/>
</ThemeProvider>
Here is the official documentation for MUI5

How to apply different color in AppBar Title MUI?

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'}}>

Resources