How to use MUI v5 makeStyles without ThemeProvider? - reactjs

I have a styles.tsx file because I rather not put the styling in my components:
//styles.tsx
import {grey, purple} from '#mui/material/colors';
import {styled, Theme} from '#mui/material/styles';
import {createStyles, makeStyles} from '#mui/styles';
export const drawerStyles = makeStyles((theme: Theme) =>
createStyles({
logo: {
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
},
slide: {
paddingLeft: '8px',
width: '100%',
},
}),
);
In another component I import the drawerStyles:
// drawerContainer.tsx
import {drawerStyles} from 'Src/styles';
export const DrawerContainer = () => {
const classes = drawerStyles();
return (
<Box className={`${classes.logo}>
<p>some text</p>
</Box>
)
The code compiles but the browser is returning an error:
MUI: The styles argument provided is invalid. You are providing a function without a theme in the context. One of the parent elements needs to use a ThemeProvider.
On my index.tsx I use ThemeProvider:
// index.tsx
import {ThemeProvider, StyledEngineProvider} from '#mui/material/styles';
import {theme} from 'Src/theme';
const Root = () => {
return (
<ApolloProvider client={client}>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<CssBaseline>
<App />
</CssBaseline>
</ThemeProvider>
</StyledEngineProvider>
</ApolloProvider>
);
};
render(<Root />, document.getElementById('root'));
I think the issue is because styles.tsx isn't inside the index.tsx scope. So it doesn't have the themeprovider context when the browser loads the file.
Should I just move all the styling in the component? Or is there another way?
// edit //
Created the styling with the styled api:
// styles.tsx
export const Logo = styled(Box)(({theme}) => ({
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
}));
// DrawerContainer.tsx
<Link data-cy='btn_home' to='/'>
<Logo component='button'>Movieseat</Logo>
</Link>
I kind of dislike this syntax, it's not clear what type of object Logo is.

See this answer for more detail. In short, makesStyles/withStyles is not the first class APIs in MUI v5 anymore and is scheduled to be removed in v6. If you use the old API, you have to add a theme yourself.
In v4 you can import makeStyles from #material-ui/core/styles without having to supply a custom theme. You can do the same in v5 but only with the new styled API that is being used by all of the MUI components internally.

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>
);
}

Is makeStyles still able to be used in MUI v5? [duplicate]

I have a styles.tsx file because I rather not put the styling in my components:
//styles.tsx
import {grey, purple} from '#mui/material/colors';
import {styled, Theme} from '#mui/material/styles';
import {createStyles, makeStyles} from '#mui/styles';
export const drawerStyles = makeStyles((theme: Theme) =>
createStyles({
logo: {
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
},
slide: {
paddingLeft: '8px',
width: '100%',
},
}),
);
In another component I import the drawerStyles:
// drawerContainer.tsx
import {drawerStyles} from 'Src/styles';
export const DrawerContainer = () => {
const classes = drawerStyles();
return (
<Box className={`${classes.logo}>
<p>some text</p>
</Box>
)
The code compiles but the browser is returning an error:
MUI: The styles argument provided is invalid. You are providing a function without a theme in the context. One of the parent elements needs to use a ThemeProvider.
On my index.tsx I use ThemeProvider:
// index.tsx
import {ThemeProvider, StyledEngineProvider} from '#mui/material/styles';
import {theme} from 'Src/theme';
const Root = () => {
return (
<ApolloProvider client={client}>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<CssBaseline>
<App />
</CssBaseline>
</ThemeProvider>
</StyledEngineProvider>
</ApolloProvider>
);
};
render(<Root />, document.getElementById('root'));
I think the issue is because styles.tsx isn't inside the index.tsx scope. So it doesn't have the themeprovider context when the browser loads the file.
Should I just move all the styling in the component? Or is there another way?
// edit //
Created the styling with the styled api:
// styles.tsx
export const Logo = styled(Box)(({theme}) => ({
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
}));
// DrawerContainer.tsx
<Link data-cy='btn_home' to='/'>
<Logo component='button'>Movieseat</Logo>
</Link>
I kind of dislike this syntax, it's not clear what type of object Logo is.
See this answer for more detail. In short, makesStyles/withStyles is not the first class APIs in MUI v5 anymore and is scheduled to be removed in v6. If you use the old API, you have to add a theme yourself.
In v4 you can import makeStyles from #material-ui/core/styles without having to supply a custom theme. You can do the same in v5 but only with the new styled API that is being used by all of the MUI components internally.

MUI errors: theme.spacing is not a function [duplicate]

I have a styles.tsx file because I rather not put the styling in my components:
//styles.tsx
import {grey, purple} from '#mui/material/colors';
import {styled, Theme} from '#mui/material/styles';
import {createStyles, makeStyles} from '#mui/styles';
export const drawerStyles = makeStyles((theme: Theme) =>
createStyles({
logo: {
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
},
slide: {
paddingLeft: '8px',
width: '100%',
},
}),
);
In another component I import the drawerStyles:
// drawerContainer.tsx
import {drawerStyles} from 'Src/styles';
export const DrawerContainer = () => {
const classes = drawerStyles();
return (
<Box className={`${classes.logo}>
<p>some text</p>
</Box>
)
The code compiles but the browser is returning an error:
MUI: The styles argument provided is invalid. You are providing a function without a theme in the context. One of the parent elements needs to use a ThemeProvider.
On my index.tsx I use ThemeProvider:
// index.tsx
import {ThemeProvider, StyledEngineProvider} from '#mui/material/styles';
import {theme} from 'Src/theme';
const Root = () => {
return (
<ApolloProvider client={client}>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<CssBaseline>
<App />
</CssBaseline>
</ThemeProvider>
</StyledEngineProvider>
</ApolloProvider>
);
};
render(<Root />, document.getElementById('root'));
I think the issue is because styles.tsx isn't inside the index.tsx scope. So it doesn't have the themeprovider context when the browser loads the file.
Should I just move all the styling in the component? Or is there another way?
// edit //
Created the styling with the styled api:
// styles.tsx
export const Logo = styled(Box)(({theme}) => ({
'fontSize': '2em',
'fontFamily': 'Oleo Script Swash Caps',
'background': 'transparent',
'border': 'none',
'marginLeft': theme.spacing(1),
'width': '41px',
'overflow': 'hidden',
'transition': 'all 0.1s ease-out',
'cursor': 'pointer',
'&:hover': {
color: purple[700],
},
}));
// DrawerContainer.tsx
<Link data-cy='btn_home' to='/'>
<Logo component='button'>Movieseat</Logo>
</Link>
I kind of dislike this syntax, it's not clear what type of object Logo is.
See this answer for more detail. In short, makesStyles/withStyles is not the first class APIs in MUI v5 anymore and is scheduled to be removed in v6. If you use the old API, you have to add a theme yourself.
In v4 you can import makeStyles from #material-ui/core/styles without having to supply a custom theme. You can do the same in v5 but only with the new styled API that is being used by all of the MUI components internally.

ReactJS: TypeError: theme.spacing is not a function

I am building a 'ReactJS' application and came across the following error:
TypeError: theme.spacing is not a function
(anonymous function)
E:/Projects/PortfolioSite/React-Portfolio-Website/react-portfolio-website/src/components/Navbar.js:39
36 | avatar:{
37 | display: "block",
38 | margin: "0.5rem auto",
> 39 | width: theme.spacing(13),
40 | heght: theme.spacing(13)
41 | }
42 | }));
I have already imported makestyles from "#material-ui/styles". But it outputs the above error:
For your reference I would like to add the complete code I used:
import React from 'react';
import {makeStyles} from "#material-ui/styles";
import {
AppBar,
Toolbar,
ListItem,
ListItemIcon,
IconButton,
ListItemText,
Avatar,
Divider,
List,
Typography,
Box
} from "#material-ui/core";
import {
ArrowBack,
AssignmentInd,
Home,
Apps,
ContactMail
} from "#material-ui/icons";
import avatar from "../Assets/Images/avatar.png";
//CSS styles
const useStyles = makeStyles( theme =>({
menuSliderContainer:{
width: 250,
background: "#511",
height: "30rem"
},
avatar:{
display: "block",
margin: "0.5rem auto",
width: theme.spacing(13),
heght: theme.spacing(13)
}
}));
const menuItems = [
{
listIcon: <Home/>,
listText: "Home"
},
{
listIcon: <AssignmentInd/>,
listText: "Resume"
},
{
listIcon: <Apps/>,
listText: "Portfolio"
},
{
listIcon: <ContactMail/>,
listText: "Contact"
},
{
listIcon: <Home/>,
listText: "Home"
}
]
const Navbar = () => {
const classes = useStyles()
return (
<>
<Box component="div" className={classes.menuSliderContainer}>
<Avatar src={avatar} className={classes.avatar} alt="Pawara Siriwardhane"/>
<Divider/>
<List>
{menuItems.map((lstItem,key)=>(
<ListItem button key={key}>
<ListItemIcon>
{lstItem.listIcon}
</ListItemIcon>
<ListItemText/>
</ListItem>
))}
</List>
</Box>
<Box component="nav">
<AppBar position="static" style={{background:"#222"}}>
<Toolbar>
<IconButton>
<ArrowBack style={{color: "tomato"}}/>
</IconButton>
<Typography variant="h5" style={{color:"tan"}}> Portfolio </Typography>
</Toolbar>
</AppBar>
</Box>
</>
)
}
export default Navbar
I have already gone through the
already asked questions: Why Material-UI is not recognizing the theme.spacing function?
& the GitHub conversation: [Grid] Use a unitless spacing API #14099
but could not find a working answer.
It happens because you don't have a material-ui theme defined on your application. Then apply the default material ui theme, or your own theme. It can be done in two ways:
Wrap your application with ThemeProvider component
Export makeStyles hook from #material-ui/core/styles instead of #material-ui/styles, in order to have the default theme.
I would like to add to previous answer pointing out that another reason for this error, once migrated from Material UI 4.xto Material 5.x and so respectively have the import from #mui/styles, assuming one has created a style object, is that indeed as in your code you are referring to the theme object that is not present anymore as default e.g:
import { makeStyles } from '#material-ui/core/styles';
export default makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8), // <-- this theme as isn't defined will
// cause the error
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: theme.spacing(2),
},
root: {
'& .MuiTextField-root': {
margin: theme.spacing(1),
},
}
if you would like to use theme default propeties then change that style to
import { makeStyles } from '#mui/styles';
import { useTheme } from '#mui/material/styles';
export default makeStyles(() => ({
paper: {
marginTop: useTheme().spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: useTheme().spacing(2),
},
root: {
'& .MuiTextField-root': {
margin: useTheme().spacing(1),
},
},
According to the latest version of MUI, you should import makeStyles from #mui/styles.
Add a ThemeProvider at the root of your application since the defaultTheme is no longer available.
If you are using this utility together with #mui/material, it's recommended that you use the ThemeProvider component from #mui/material/styles

Global Styles with React and MUI

I'm new to React and MUI but I have to write an enterprise application with a nice styling. I would like to use some kind of global styles for my application (to be able to change it later on
) with functional components in react (maybe I will later add redux).
What's the best practice approach for global styles with react and material (latest versions)?
What about this one (ThemeProvider): https://material-ui.com/styles/advanced/?
I read about MuiThemeProvider but could not find it in the material version 4 documentation. Is it obsolete? What's the difference between MuiThemeProvider and ThemeProvider?
React (client side rendering) & Material (latest versions)
Backend: Node
In Material-UI v5, you can use GlobalStyles to do exactly that. From what I know, GlobalStyles is just a wrapper of emotion's Global component. The usage is pretty straightforward:
import GlobalStyles from "#mui/material/GlobalStyles";
<GlobalStyles
styles={{
h1: { color: "red" },
h2: { color: "green" },
body: { backgroundColor: "lightpink" }
}}
/>
Note that you don't even have to put it inside ThemeProvider, GlobalStyles uses the defaultTheme if not provided any:
return (
<>
<GlobalStyles
styles={(theme) => ({
h1: { color: theme.palette.primary.main },
h2: { color: "green" },
body: { backgroundColor: "lightpink" }
})}
/>
<h1>This is a h1 element</h1>
<h2>This is a h2 element</h2>
</>
);
Live Demo
You can actually write global styles with material UI:
const useStyles = makeStyles((theme) => ({
'#global': {
'.MuiPickersSlideTransition-transitionContainer.MuiPickersCalendarHeader-transitionContainer': {
order: -1,
},
'.MuiTypography-root.MuiTypography-body1.MuiTypography-alignCenter': {
fontWeight: 'bold',
}
}
}));
Global Styles with Material UI & React
// 1. GlobalStyles.js
import { createStyles, makeStyles } from '#material-ui/core';
const useStyles = makeStyles(() =>
createStyles({
'#global': {
html: {
'-webkit-font-smoothing': 'antialiased',
'-moz-osx-font-smoothing': 'grayscale',
height: '100%',
width: '100%'
},
'*, *::before, *::after': {
boxSizing: 'inherit'
},
body: {
height: '100%',
width: '100%'
},
'#root': {
height: '100%',
width: '100%'
}
}
})
);
const GlobalStyles = () => {
useStyles();
return null;
};
export default GlobalStyles;
** Then Use it in App.js like below**
// 2. App.js
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import { Router } from 'react-router-dom';
import { NavBar, Routes, GlobalStyles, Routes } from '../';
const theme = createMuiTheme({
palette: {
primary: {
main: 'blue'
}
}
});
const App = () => {
return (
<MuiThemeProvider theme={theme}>
<Router>
<NavBar />
<GlobalStyles />
<Routes />
</Router>
</MuiThemeProvider>
);
};
export default App;
This Works for me with my react project.
For global styles you can use it like shown below.
This is the best implementation that has worked for me.
const theme = createMuiTheme({
overrides: {
MuiCssBaseline: {
'#global': {
html: {
WebkitFontSmoothing: 'auto',
},
},
},
},
});
// ...
return (
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
);
For more reference: Global CSS
In my experience, using MuiThemeProvider and createMuiTheme have worked wonderfully. However, I am using Material-UI version 3.9.2.
MuiThemeProvider should wrap around your entire application. All you need to do in all of your components would be to instead of passing your styles object to with styles, pass a function that passes in the theme.
Ex:
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import {NavBar, Routes} from '../'
const theme = createMuiTheme({
palette: {
primary: {
main: 'red'
},
},
/* whatever else you want to add here */
});
class App extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
<NavBar />
<Routes />
</MuiThemeProvider>
)
}
then in navbar let's say:
import React from 'react';
import { withStyles } from '#material-ui/core';
const styles = theme => ({
root: {
color: theme.palette.primary.main,,
}
})
const NavBar = ({classes}) => {
return <div className={classes.root}>navigation</div>
}
export default withStyles(styles)(NavBar);
Hope that helps, works very well for me!

Resources