Reputation: 1096
I'm using CRA with Material-ui and Styled Components type of styling. When building my CSS I want to access Material-ui's default theme.
part of package.json:
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"@material-ui/core": "^4.2.1",
"@material-ui/icons": "^4.2.1",
"@material-ui/styles": "^4.2.1",
"styled-components": "^4.3.2"
}
When I try the below theme
exists on props
but is an empty object.
StyledApp.js:
import styled from "styled-components";
import Button from "@material-ui/core/Button";
export const StyledButtonUsingTheme = styled(Button)`
//Below will give "Cannot read property 'error' of undefined"
background-color: ${props => props.theme.palette.error.light};
`;
App.js:
import React from "react";
import "./App.css";
import { StylesProvider, ThemeProvider } from "@material-ui/styles";
import { createMuiTheme } from "@material-ui/core/styles";
import { StyledButtonUsingTheme } from "./StyledApp";
function App() {
const defaultTheme = createMuiTheme();
window.console.log("Default theme passing to ThemeProvider", defaultTheme);
return (
<StylesProvider injectFirst>
<ThemeProvider theme={defaultTheme}>
<div className="App">
<StyledButtonUsingTheme variant="outlined">
Styled Button Using Theme
</StyledButtonUsingTheme>
</div>
</ThemeProvider>
</StylesProvider>
);
}
export default App;
The console.log in App.js
shows the whole theme object, and that's what I pass to ThemesProvider. Interestingly props.theme
is there! but sadly with no values.
Upvotes: 27
Views: 36591
Reputation: 156
Just to update for mui 5 using @mui/system
import { Box, useTheme } from "@mui/material";
import { styled } from "@mui/system";
const StyledBox = styled(Box)(({ theme }) => ({
padding: `0 ${theme.spacing(2)}`,
backgroundColor: theme.palette.background.default,
width: "100%",
}));
Upvotes: 0
Reputation: 552
While many of the answers here tell you to use multiple theme providers, that is unnecessary with MUI5 as there is a special version of their styled engine that you can install to replace the default emotion based one.
If you use that, there is also no need to wrap your styled components within useTheme
or similar features. You can just "magically" access the theme by accessing the props:
import styled from 'styled-components';
const Example = styled.span`
background-color: ${props => props.theme.palette.primary.main};
`
If you get errors about undefined theme vars even after installing @mui/styled-engine-sc
, you might need to update your bundler configuration.
The official docs have info for webpack and next.js as well as a config snippet you need if you're using typescript.
If you're using vite, you need to add the following to your vite.config.[j|t]s
:
resolve: {
alias: {
'@mui/styled-engine': '@mui/styled-engine-sc',
},
},
Upvotes: 0
Reputation: 988
I did it in MUI v5 like this
import { styled as muiStyled } from '@mui/material';
const NavLinkStyle = muiStyled('div')(({ theme }) => ({
padding: '0 10px',
height: '100%',
fontWeight: 'bold',
'&:hover': {
color: theme.palette.primary.main,
cursor: 'pointer',
borderRadius: '15px'
}
}));
Upvotes: 5
Reputation: 25182
For MUI v5:
index.tsx
import { ThemeProvider, createTheme } from "@mui/material/styles";
import { StyledEngineProvider} from "@mui/material";
import { ThemeProvider as ScThemeProvider } from "styled-components";
import App from "components/App/App";
const theme = createTheme();
ReactDOM.render(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<ScThemeProvider theme={theme}>
<App />
</ScThemeProvider>
</ThemeProvider>
</StyledEngineProvider>,
document.getElementById("root")
);
Upvotes: 4
Reputation: 130
In my case, I found that the theme
object is automatically passed in with the styled
component and can be accessed via parameter as follows:
import React from 'react';
import { styled } from '@material-ui/core';
const StyledButton = styled('button')(({ theme }) => ({
color: theme.palette.text.secondary,
}));
I have this working in MUI v4.11.0.
Upvotes: 2
Reputation: 139
in your styled component you can use the hooks useTheme example :
import { useTheme } from "@material-ui/core"
import { styled } from "@material-ui/styles"
const theme = useTheme
const StyledListbox = styled("ul")({
backgroundColor: theme.palette.primary.main,
})
Upvotes: 0
Reputation: 61
If you want to use both ThemeProviders, first from styled-components and second from material-ui, you can use alias for one of them:
import { ThemeProvider as StyledThemeProvider} from 'styled-components';
import { ThemeProvider } from '@material-ui/core/styles';
function App() {
return (
<Router>
<ThemeProvider theme={theme}>
<StyledThemeProvider theme={theme}>
<Wrapper>
<TheHeader />
<TheContent />
<TheFooter />
</Wrapper>
</StyledThemeProvider>
</ThemeProvider>
</Router >
);
}
export default App;
Upvotes: 3
Reputation: 1305
The answer which used withTheme is almost complete. The last part didn't work for me, so I changed to:
import styled from 'styled-components'
import { withTheme } from "@material-ui/core/styles"
const StyledButton = withTheme(styled('h1')`
background-color: ${props => props.theme.palette.error.light};
`
)
Upvotes: 7
Reputation: 973
You could use withTheme :
App.js
import React from "react"
import { ThemeProvider, createMuiTheme } from "@material-ui/core/styles"
import { StyledButton } from "./StyledButton"
const App = () => {
const theme = createMuiTheme();
return (
<ThemeProvider theme={theme}>
<StyledButton />
</ThemeProvider>
)
}
export default App
StyledButton.js
import { styled, withTheme } from "@material-ui/core/styles"
import Button from "@material-ui/core/Button"
export const StyledButton= styled(withTheme(Button))(props => ({
background: props.theme.palette.background.paper,
}))
Upvotes: 22
Reputation: 1605
As Horyd in the comment says, using the ThemeProvider
from Styled-Components
will give you access to the theme properties inside your styled component.
But Material-UI doesn't apply that theme anymore to its own components.
The workaround I found is as ugly as it is simple: Use both Themeproviders. So Material-UI applies the theme to its components and you can access the theme in your styled components.
import { ThemeProvider } from "styled-components";
import { MuiThemeProvider,StylesProvider } from "@material-ui/core/styles";
ReactDOM.render(
//Make sure the Material stylesheet is placed above your own
//styles so you can overwrite them
<StylesProvider injectFirst>
//Use the theme in the ThemeProvider for Material-UI so
//styles are applied to the Material-UI components
<MuiThemeProvider theme={theme}>
//Use also the ThemeProvider for Styled-Components so
//you can access the theme in your own css
<ThemeProvider theme={theme}>
//Include your app and you have acces to everything
<App />
</ThemeProvider>
</MuiThemeProvider>
</StylesProvider>,
document.getElementById("app"));
Upvotes: 23
Reputation: 1096
Problem Solved!
The solution is to use:
import { ThemeProvider } from "styled-components";
in App.js then the theme
is there with all the values on the props
object.
I used ThemeProvider from "@material-ui/styles" in App.js
import { StylesProvider, ThemeProvider } from "@material-ui/styles";
That doesn't play well with `import styled from "styled-components" in StyledApp.js
The working two files:
App.js
import React from "react";
import "./App.css";
import { StylesProvider } from "@material-ui/styles";
import { ThemeProvider } from "styled-components";
import { createMuiTheme } from "@material-ui/core/styles";
import { StyledButtonUsingTheme } from "./StyledApp";
function App() {
const defaultTheme = createMuiTheme();
window.console.log("Default theme passing to ThemeProvider", defaultTheme);
return (
<StylesProvider injectFirst>
<ThemeProvider theme={defaultTheme}>
<div className="App">
<StyledButtonUsingTheme variant="outlined">
Styled Button Using Theme
</StyledButtonUsingTheme>
</div>
</ThemeProvider>
</StylesProvider>
);
}
export default App;
StyledApp.js
import styled from "styled-components";
import Button from "@material-ui/core/Button";
export const StyledButtonUsingTheme = styled(Button)`
//Below will work now!
background-color: ${props => props.theme.palette.error.light};
`;
Upvotes: 8