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

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

Related

Why this customTheme is not applied to my buttons

Why this customTheme is not applied to my buttons. I'm using the MUI 5. Please tell me where I'm making the mistakes & how to resolve this.
import React from 'react';
import NavBar from './components/NavBar';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import { Button } from '#mui/material';
const customTheme = createTheme({
overrides: {
MuiButton: {
outlined: {
backgroundImage: 'linear-gradient(to top, #d299c2 0%, #fef9d7 100%)',
color: 'green'
},
text: {
color: "red"
}
}
}
})
function App() {
return (
<div id='appDiv2'>
<ThemeProvider theme={customTheme}>
<NavBar />
<Button variant='outlined'> Test Button </Button>
</ThemeProvider>
<DirectionSnackbar />
</div>
);
}
export default App;
The structure of the theme object depends on the version of MaterialUI. If you use latest, the scheme should be
const theme = createTheme({
components: {
// Name of the component
MuiButton: {
styleOverrides: {
// Name of the slot
outlined: {
backgroundImage: 'linear-gradient(to top, #d299c2 0%, #fef9d7 100%)',
color: 'green'
},
text: {
color: "red"
}
},
},
},
});
https://mui.com/customization/theme-components/#global-style-overrides

How custom fontFamily Chip rect material-ui

I want to custom font famaily Chip but it doesn't work .................................................................................................................................................
import { createMuiTheme } from '#material-ui/core';
import overrides from './overrides';
import palette from './palette';
import typography from './typography';
const theme = createMuiTheme({
palette,
typography,
overrides,
});
export default theme;
import MuiChip from './MuiChip';
import MuiTooltip from './MuiTooltip';
export default {
MuiTooltip,
MuiChip
};
export default {
chip: {
fontFamily: ['prompt'].join(',')
}
};
You can override the default theme by using createMuiTheme and then wrap the component under as below
import { createMuiTheme } from '#material-ui/core/styles';
import { ThemeProvider } from '#material-ui/core';
const theme = createMuiTheme({
overrides: {
MuiChip: {
root: {
padding: '3px 4px',
fontFamily: "'Bree Serif', sans-serif",
fontSize: "15px"
},
},
},
});
export default Component = props => {
return (
<ThemeProvider theme={theme}>
<Chip size="small" label="Basic" />
</ThemeProvider>
);
}

React material how to theming body color

Is there a way to change the default body color
using CssBaseline in react material?
I don't want using like
typography: {
h2: {
color: "red",
},
},
but globally is this possible ?
I don't find any example.
UPDATE
It works with
const theme = createMuiTheme({
overrides: {
MuiCssBaseline: {
"#global": {
body: {
backgroundColor: "red",
color: "green",
},
},
},
},
});
Watch out you must have CssBaseline nested to MuiThemeProvider
<MuiThemeProvider theme={theme}>
<CssBaseline />
<App />
</MuiThemeProvider>
Here is the example of how you can set background color globally, similarly you can add typography configurations in the theme
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import CssBaseline from "#material-ui/core/CssBaseline";
const theme = createMuiTheme({
palette: {
background: {
default: "#303030"
}
}
});
function App() {
return (
<MuiThemeProvider theme={theme}>
<React.Fragment>
<CssBaseline />
<Your Componennt />
</React.Fragment>
</MuiThemeProvider>
);
}
Hope this works for you :)
Yes, brother, you can override everything globally in material UI, Here I write some Inputs, Buttons, Labels globally.
import React, { Component } from "react";
import { Box, CssBaseline } from "#material-ui/core";
import { createMuiTheme, MuiThemeProvider } from "#material-ui/core/styles";
import App from "../App";
class Layout extends Component {
/**
* Render
*/
render() {
const theme = createMuiTheme({
palette: {
secondary: {
light: "green",
main: "green",
dark: "green",
boxShadow: "none",
},
background: {
default: "red",
},
},
});
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
<Box component="div">
<App />
</Box>
</MuiThemeProvider>
);
}
}
export default Layout;

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!

How do I apply a Font Theme in React Material-UI?

I'm trying to apply a google font to my Material-UI react project, but can't seem to get it to take. I'm using mui 0.14.2.
My index.html font load:
<link href='https://fonts.googleapis.com/css?family=PT+Sans:400,700' rel='stylesheet' type='text/css'>
My component where I apply the theme:
import ThemeManager from 'material-ui/lib/styles/theme-manager';
import LightRawTheme from 'material-ui/lib/styles/raw-themes/light-raw-theme';
const App = React.createClass({
childContextTypes: {
muiTheme: React.PropTypes.object,
},
getChildContext: function() {
return {
muiTheme: ThemeManager.modifyRawThemeFontFamily(ThemeManager.getMuiTheme(LightRawTheme), 'PT Sans, sans-serif')
}
},
...etc etc
}
The other answers don't seem to work for Material-UI v1. Here's what worked for me:
import { createMuiTheme } from 'material-ui/styles';
import createPalette from 'material-ui/styles/palette';
import createTypography from 'material-ui/styles/typography';
const theme = createMuiTheme({
typography: createTypography(createPalette(), {
fontFamily: '"Comic Sans"',
})
});
class App extends Component {
render() {
return (
<MuiThemeProvider theme={theme}>
Here's another example for overriding the font while using the dark theme:
const theme = (() => {
const palette = createPalette({
type: 'dark',
});
const typography = createTypography(palette, {
fontFamily: '"Comic Sans"',
});
return createMuiTheme({
palette: palette,
typography: typography,
});
})();
The typography documentation for v1 is here although I had trouble getting the example working: https://material-ui-1dab0.firebaseapp.com/customization/themes#typography
If you're just looking to change the font of your material-ui theme, change muiTheme in the MuiThemeProvider provider component. The docs have an example here: http://www.material-ui.com/#/customization/themes
Should look something like this:
App.css
/* Load in your font */
#import url('https://fonts.googleapis.com/css?family=Lato');
App.js
// App.js
import './App.css'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
const font = "'Lato', sans-serif";
const muiTheme = getMuiTheme({
fontFamily: font
});
function App(props) {
return(
<MuiThemeProvider muiTheme={muiTheme}>
<div style={{fontFamily: font}}>...</div>
</MuiThemeProvider>
);
}
Note most of the components had to have their fonts updated, but I added fontFamily to the enclosing div (as seen above) as well in order for all to be updated (headers specifically for me).
If you're wondering what else you can override, it is probably easiest to just look at the code (https://github.com/callemall/material-ui/blob/master/src/styles/getMuiTheme.js) where it is defined
I figured this out. I did 2 things, the first of which I don't think mattered:
I switched to using a full raw theme, then implementing in-component like this:
getChildContext: function() {
return {
muiTheme: ThemeManager.getMuiTheme(rawTheme)
}
},
The second thing, which was more likely the culprit, was escaping the space in 'PT Sans', as follows:
//theme.js
import Colors from 'material-ui/lib/styles/colors';
import ColorManipulator from 'material-ui/lib/utils/color-manipulator';
import Spacing from 'material-ui/lib/styles/spacing';
import zIndex from 'material-ui/lib/styles/zIndex';
export default {
spacing: Spacing,
zIndex: zIndex,
fontFamily: 'PT\ Sans',
palette: {
primary1Color: Colors.cyan500,
primary2Color: Colors.cyan700,
primary3Color: Colors.lightBlack,
accent1Color: Colors.pinkA200,
accent2Color: Colors.grey100,
accent3Color: Colors.grey500,
textColor: Colors.darkBlack,
alternateTextColor: Colors.white,
canvasColor: Colors.white,
borderColor: Colors.grey300,
disabledColor: ColorManipulator.fade(Colors.darkBlack, 0.3),
pickerHeaderColor: Colors.cyan500,
}
};
Voila, as mundane and uninteresting a bug as you could hope for.
I'm using Material-UI version 3.9.2. I found this work-around.
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles'
import Typography from '#material-ui/core/Typography'
const theme = createMuiTheme({
palette: {
primary: { main: '#228e22' },
secondary: { main: '#4d4d4d' },
},
typography: {
useNextVariants: true,
fontFamily: '"Montserrat", Arial, Helvetica, sans-serif',
},
})
const Base = () => (
<MuiThemeProvider theme={theme}>
<Typography component="h1" variant="h1">
Hello
</Typography>
</MuiThemeProvider>
)
I use The bellow code and the result was successful. write the javascript bellow code in your own file and then write the #font-face in its CSS file:
import './App.css';
import { createMuiTheme, MuiThemeProvider } from '#material-ui/core/styles';
import createPalette from '#material-ui/core/styles/createPalette';
import createTypography from '#material-ui/core/styles/createTypography';
const theme = createMuiTheme({
typography: createTypography(createPalette({}), {
fontFamily: '"IRANSansWeb"'
}),
});
function App() {
return(
<MuiThemeProvider theme={theme}>
</MuiThemeProvider>
);
}
#font-face{
font-family: "IRANSansWeb";
src: url('./fonts/iransans/ttf/IRANSansWeb.ttf') format('ttf'),
url('./fonts/iransans/eot/IRANSansWeb.eot') format('eot'),
url('./fonts/iransans/woff/IRANSansWeb.woff') format('woff'),
url('./fonts/iransans/woff2/IRANSansWeb.woff2') format('woff2')
}
After update Material UI to:
"#mui/icons-material": "^5.0.4",
"#mui/lab": "^5.0.0-alpha.51",
"#mui/material": "^5.0.4",
"#mui/styles": "^5.0.1",
In your theme.js
import { createTheme } from "#mui/material/styles";
// Create a theme instance.
const theme = createTheme({
typography: {
fontFamily: '"Merienda", cursive',
},
palette: {
primary: {
main: "rgb(68, 139, 68)",
},
secondary: {
main: "rgb(141, 202, 141)",
// contrastText: "#fff",
},
spacing: 24,
},
});
export default theme;

Resources