MUI errors: theme.spacing is not a function [duplicate] - 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.

How to use MUI v5 makeStyles without ThemeProvider?

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

'Undefined' when attempting to pass MaterialUI theme props to styled components

I'm attempting to access my Material-UI theme props within a styled component, however I keep getting...
TypeError: Cannot read property 'primary' of undefined or similar errors in the browser.
Here is my custom theme (index.ts)
import { createMuiTheme } from "#material-ui/core";
import { blue } from "#material-ui/core/colors";
const theme = createMuiTheme({
palette: {
primary: {
main: blue[800],
contrastText: "#FFF"
},
secondary: {
main: blue[600],
contrastText: "#FFF"
}
},
typography : {
fontFamily: [
"Nunito",
"Roboto",
].join(",")
}
});
export default theme;
Here is where my theme wraps my application in the App.tsx
// Other imports
import theme from "../../app/theme/index";
const App: React.FC = () => {
return (
<>
<StylesProvider injectFirst>
<ThemeProvider theme={theme}>
// Routing stuff
</ThemeProvider>
</StylesProvider>
</>
);
};
export default App;
And here is where I am attempting to use my styled component
import { ListItem } from "#material-ui/core";
import React from "react";
import styled from "styled-components";
const Brand = styled(ListItem)`
background-color: ${props => props.theme.palette.primary.dark},
padding: ${props => props.theme.spacing(1)},
font-size: ${props => props.theme.typography.h6.fontSize},
font-weight: ${props => props.theme.typography.fontWeightMedium},
color: "white",
min-height: "64px",
padding-left: ${props => props.theme.spacing(6)}
`;
const SidebarNew: React.FC = () => {
return (
<Brand button>
// Stuff
</Brand>
);
};
export default SidebarNew;
This compiles but fails in the browser. What am I missing here?
If I use material-ui's built in styled like below, it appears to work, however I would prefer to use styled-components directly
const Brand = styled(ListItem)(({ theme }) => ({
backgroundColor: theme.palette.primary.dark,
padding: theme.spacing(1),
fontSize: theme.typography.h6.fontSize,
fontWeight: theme.typography.fontWeightMedium,
color: "white",
minHeight: 64,
paddingLeft: theme.spacing(6)
}));
You need to use ThemeProvider from styled-components (SCThemeProvider in the example below) in addition to the Material-UI ThemeProvider; otherwise styled-components won't know about your theme.
Here is a working example:
import {
createMuiTheme,
StylesProvider,
ThemeProvider
} from "#material-ui/core";
import { ThemeProvider as SCThemeProvider } from "styled-components";
import * as React from "react";
import Dashboard from "./Dashboard";
import "./styles.css";
const theme = createMuiTheme({
palette: {
primary: {
main: "#1a1aff",
contrastText: "#FFF"
},
secondary: {
main: "#ff3333",
contrastText: "#FFF"
}
},
typography: {
h5: {
fontSize: "10px"
}
}
});
export default function App() {
return (
<StylesProvider injectFirst>
<ThemeProvider theme={theme}>
<SCThemeProvider theme={theme}>
<Dashboard />
</SCThemeProvider>
</ThemeProvider>
</StylesProvider>
);
}

Resources