How to use useTheme hook from Material-UI? - reactjs

There is an example of use of useTheme hook on Material-UI website: https://material-ui.com/styles/advanced/#theming
And code here:
import React from 'react';
import { ThemeProvider, useTheme } from '#material-ui/styles';
function DeepChild() {
const theme = useTheme();
return <span>{`spacing ${theme.spacing}`}</span>;
}
function UseTheme() {
return (
<ThemeProvider
theme={{
spacing: '8px',
}}
>
<DeepChild />
</ThemeProvider>
);
}
export default UseTheme;
But it doesn't show how to inject the theme. When I try to inject some properties with className it doesn't do anything. Code here:
import React from "react";
import { ThemeProvider, useTheme } from "#material-ui/styles";
function DeepChild() {
const theme = useTheme();
return <div className={theme}> eldfo elo </div>;
}
function App() {
return (
<ThemeProvider
theme={{
spacing: "40px",
color: "yellow",
fontSize: "30px"
}}
>
<DeepChild />
</ThemeProvider>
);
}
export default App;
My question is how to inject it correctly?

Use it just like any other React hook:
function App() {
const theme = useTheme<Theme>()
const space = theme.spacing(1)
return <p>Space: {space}</p>
}
Note that what you get is the full theme. If you want to get any class name, you should use theme.className but you did not define a className property in your theme example.
What you want to do is probably:
import React from "react";
import { ThemeProvider, useTheme } from "#material-ui/styles";
function DeepChild() {
const theme = useTheme();
return <div className={theme.divClass}> eldfo elo </div>;
}
function App() {
return (
<ThemeProvider
theme={{
divClass: {
spacing: "40px",
color: "yellow",
fontSize: "30px"
}
}}
>
<DeepChild />
</ThemeProvider>
);
}
export default App;

Related

Toggling button image in React

I'm trying to toggle an icon in a button in react but I've tried everything and nothing works. I can change the background/text color toggling onClick but I'm missing something to change the icon and I don't know what! Any help?
Here's my code:
App.js
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { useState } from "react";
import Layout from "./layout";
import ThemeContext, { themes } from "./theme-context";
import { faSun, faMoon } from '#fortawesome/free-solid-svg-icons'
function App() {
const sun = <FontAwesomeIcon icon={faSun} />
const moon = <FontAwesomeIcon icon={faMoon} />
const [theme, setTheme] = useState(themes.dark)
const toggleTheme = () => theme === themes.dark ? setTheme(themes.light) : setTheme(themes.dark)
return (
<ThemeContext.Provider value={theme}>
<button onClick={toggleTheme}>
{sun}
</button>
<Layout />
</ThemeContext.Provider>
);
}
export default App;
theme-context.js
import React from "react"
export const themes = {
dark: {
color: "white",
background: "black",
padding: "5px",
width: "200px",
textAlign: "center",
},
light: {
color: "black",
background: "white",
padding: "5px",
width: "200px",
textAlign: "center",
}
}
const ThemeContext = React.createContext(themes.dark)
export default ThemeContext;
layout.jsx
import React, { useContext } from "react";
import ThemeContext from "./theme-context";
const Layout = () =>{
const theme = useContext(ThemeContext)
return (
<div style={theme} >
<p>This is your content</p>
</div>
)
}
export default Layout;
I have tried {themes.dark? : {sun} ? {moon}} but it didn't work.
The {themes.dark? : {sun} ? {moon}} was very close to correct (concept-wise, the syntax is not correct though). What you needed to do instead is { theme === themes.dark ? sun : moon } With your original snippet, you were just checking to see if themes.dark was truthy, which will always return true because it is an object. What you needed to do was check to see if the current theme was the same as themes.dark.
Hope this helps.

MUI v5 cant' change primary color of any components [duplicate]

I have created a theme in the index of my React.JS project using MUI. When I try to apply my style to my Appbar the theme does not correctly modify the menu button nor the menu itself. the button looks generic default and the menu remains white when it should match the color of the Appbar itself.
My index.tsx looks as such:
import React from "react";
import ReactDOM from "react-dom";
import AppbarTop from "./AppbarTop";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import { LocalizationProvider } from "#mui/lab";
import { createTheme } from "#mui/material";
import { ThemeProvider } from "#mui/styles";
import { StyledEngineProvider } from "#mui/material/styles";
const customHistory = createBrowserHistory();
const theme = createTheme({
palette: {
primary: {
main: "#242526"
},
secondary: {
main: "#d975d0"
},
text: {
primary: "#E4E6EB",
secondary: "#B0B3B8"
},
background: {
default: "#242526",
paper: "#242526"
}
}
});
ReactDOM.render(
<React.StrictMode>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Router history={customHistory}>
<ThemeProvider theme={theme}>
<StyledEngineProvider injectFirst>
<AppbarTop />
</StyledEngineProvider>
</ThemeProvider>
</Router>
</LocalizationProvider>
</React.StrictMode>,
document.getElementById("root")
);
My appbar.tsx looks like this:
import React from "react";
import {
AppBar,
Box,
Button,
Container,
Menu,
MenuItem,
Toolbar
} from "#mui/material";
import HomeIcon from "#mui/icons-material/Home";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme?: any) => ({
appBar: {
background: theme.palette.primary.main,
height: "60px",
position: "relative"
}
}));
const AppbarTop: React.FC<{ [key: string]: any }> = () => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<any>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<Button
id="basic-button"
aria-controls="basic-menu"
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button"
}}
>
<MenuItem onClick={handleClose}>
<HomeIcon />{" "}
</MenuItem>
</Menu>
{/*test speed dial*/}
<Container maxWidth="sm"></Container>
<Box></Box>
</Toolbar>
</AppBar>
</>
);
};
export default AppbarTop;
Can someone please explain what I am missing?
Change this line:
import { ThemeProvider } from "#mui/styles";
To:
import { ThemeProvider } from "#mui/material/styles";
Reason: There are 2 ThemeProviders here
The one from #mui/styles: This ThemeProvider does send the Theme object down via context, it works fine, you can still access it using the useTheme hook:
const theme = useTheme();
return <Box sx={{ width: 10, height: 10, bgcolor: theme.palette.primary.main }} />
The one from #mui/material/styles: This ThemeProvider is a wrapper of the above, but it also injects the theme to the StyledEngineThemeContext.Provider, which allows you to access the theme when using MUI API (sx prop/styled()). The problem here is that the Button and Menu components uses the styled() API under-the-hood so the ThemeProvider needs to be imported from #mui/material/styles to make it work.
return <Box sx={{ width: 10, height: 10, bgcolor: 'primary.main' }} />
Related answers
Difference between #mui/material/styles and #mui/styles?
Cannot use palette colors from MUI theme
MUI - makeStyles - Cannot read properties of undefined
Material UI Dark Mode

TypeError: Cannot read properties of undefined (reading 'breakpoints') in material ui [duplicate]

I have created a theme in the index of my React.JS project using MUI. When I try to apply my style to my Appbar the theme does not correctly modify the menu button nor the menu itself. the button looks generic default and the menu remains white when it should match the color of the Appbar itself.
My index.tsx looks as such:
import React from "react";
import ReactDOM from "react-dom";
import AppbarTop from "./AppbarTop";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import { LocalizationProvider } from "#mui/lab";
import { createTheme } from "#mui/material";
import { ThemeProvider } from "#mui/styles";
import { StyledEngineProvider } from "#mui/material/styles";
const customHistory = createBrowserHistory();
const theme = createTheme({
palette: {
primary: {
main: "#242526"
},
secondary: {
main: "#d975d0"
},
text: {
primary: "#E4E6EB",
secondary: "#B0B3B8"
},
background: {
default: "#242526",
paper: "#242526"
}
}
});
ReactDOM.render(
<React.StrictMode>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Router history={customHistory}>
<ThemeProvider theme={theme}>
<StyledEngineProvider injectFirst>
<AppbarTop />
</StyledEngineProvider>
</ThemeProvider>
</Router>
</LocalizationProvider>
</React.StrictMode>,
document.getElementById("root")
);
My appbar.tsx looks like this:
import React from "react";
import {
AppBar,
Box,
Button,
Container,
Menu,
MenuItem,
Toolbar
} from "#mui/material";
import HomeIcon from "#mui/icons-material/Home";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme?: any) => ({
appBar: {
background: theme.palette.primary.main,
height: "60px",
position: "relative"
}
}));
const AppbarTop: React.FC<{ [key: string]: any }> = () => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<any>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<Button
id="basic-button"
aria-controls="basic-menu"
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button"
}}
>
<MenuItem onClick={handleClose}>
<HomeIcon />{" "}
</MenuItem>
</Menu>
{/*test speed dial*/}
<Container maxWidth="sm"></Container>
<Box></Box>
</Toolbar>
</AppBar>
</>
);
};
export default AppbarTop;
Can someone please explain what I am missing?
Change this line:
import { ThemeProvider } from "#mui/styles";
To:
import { ThemeProvider } from "#mui/material/styles";
Reason: There are 2 ThemeProviders here
The one from #mui/styles: This ThemeProvider does send the Theme object down via context, it works fine, you can still access it using the useTheme hook:
const theme = useTheme();
return <Box sx={{ width: 10, height: 10, bgcolor: theme.palette.primary.main }} />
The one from #mui/material/styles: This ThemeProvider is a wrapper of the above, but it also injects the theme to the StyledEngineThemeContext.Provider, which allows you to access the theme when using MUI API (sx prop/styled()). The problem here is that the Button and Menu components uses the styled() API under-the-hood so the ThemeProvider needs to be imported from #mui/material/styles to make it work.
return <Box sx={{ width: 10, height: 10, bgcolor: 'primary.main' }} />
Related answers
Difference between #mui/material/styles and #mui/styles?
Cannot use palette colors from MUI theme
MUI - makeStyles - Cannot read properties of undefined
Material UI Dark Mode

How to change the color of the primary Material UI

I have theme like this:
export const Original = createMuiTheme({
palette: {
type: 'light',
primary: {
light: '#b2dfdb',
main: '#26a69a',
dark: '#004d40',
}
}
});
And I use it for this:
<ListItem color = 'primary' button >
<img src={APP} alt='' />
</ListItem>
how can I use the primary-light or primary-dark for ListItem
If you read Material UI documentation. You would know that List & ListItem don't have props color. Thus in order for you to add one or apply any other colors as you wish, you can do something like this:-
App.js (require: ThemeProvider & createMuiTheme from #material-ui/core/styles)
import React from "react";
import { ThemeProvider, createMuiTheme } from "#material-ui/core/styles";
import "./style.css";
import Demo from "./Demo";
export default function App() {
const lightTheme = createMuiTheme({
palette: {
type: "light",
primary: {
light: "#b2dfdb",
main: "#26a69a",
dark: "#004d40"
}
}
});
return (
<ThemeProvider theme={lightTheme}>
<Demo />
</ThemeProvider>
);
}
Demo.js (require: makeStyles or 'useTheme' from #material-ui/stlyes):-
import React from "react";
import { makeStyles, useTheme } from "#material-ui/styles";
import { List, ListItem } from "#material-ui/core";
import "./style.css";
const Demo = () => {
const classes = useStyles();
const theme = useTheme();
return (
<>
<List>
<ListItem className={classes.listItem}>
Using useStyles (classes)
</ListItem>
<ListItem style={{ color: theme.palette.primary.dark }}>
Using inline direct theme
</ListItem>
</List>
<List className={classes.list}>
<ListItem>Having List control over all ListItem styles</ListItem>
</List>
</>
);
};
export default Demo;
const useStyles = makeStyles(theme => ({
listItem: {
color: theme.palette.primary.light
},
list: {
color: theme.palette.primary.main
}
}));
Here are the working sandbox code you can refer to.

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