material-ui : enable the dark mode automatically - javascript

As per the documentation:
It says dark mode theme will be generated automatically and get reflected in UI, but it is not working for me.
Dependencies:
"#emotion/styled": "^11.0.0",
"#material-ui/core": "^5.0.0-alpha.16",
"#material-ui/icons": "^5.0.0-alpha.15",
"#material-ui/lab": "^5.0.0-alpha.16",
Code:
import { createMuiTheme } from "#material-ui/core/styles";
import { CssBaseline, ThemeProvider, useMediaQuery } from "#material-ui/core";
import { green, purple } from "#material-ui/core/colors";
import { useEffect, useMemo } from "react";
import { Route, Switch, useHistory } from "react-router-dom";
import SignIn from "./ui/auth/SignIn.js";
import SignUp from "./ui/auth/SignUp.js";
import Welcome from "./ui/auth/Welcome.js";
import { log } from "./util/logger.js";
const App = () => {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = useMemo(
() => {
log(prefersDarkMode, "Dark Mode");
const themeOptions = {
palette: {
type: prefersDarkMode ? 'dark' : 'light',
primary: purple,
secondary: green
},
}
log(JSON.stringify(themeOptions), "Theme Option")
const theme = createMuiTheme(themeOptions);
log(theme, "Theme");
return theme;
},
[prefersDarkMode],
);
const history = useHistory()
useEffect(() => {
const timer = setTimeout(() => {
history.push("/signin");
}, 3000);
return function cleanup() {
clearTimeout(timer);
};
});
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Switch>
<Route path="/" component={Welcome} exact />
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Switch>
</ThemeProvider>
);
}
export default App;
Signup.js
import React, { useState } from 'react';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import Link from '#material-ui/core/Link';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
import { makeStyles } from '#material-ui/core/styles';
import Container from '#material-ui/core/Container';
import ForgotPassword from './ForgotPassword';
import { useHistory } from 'react-router-dom';
const Copyright = () => {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>
{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
background: theme.palette.background.default
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
const SignIn = () => {
const classes = useStyles();
const history = useHistory();
// Forgot Password State
const [open, setOpen] = useState(false);
function openForgotPassword(event) {
event.preventDefault();
setOpen(true);
}
function onClose() {
setOpen(false);
}
function goToSignUp(event) {
event.preventDefault();
history.push('/signup');
}
return (
<Container component="main" maxWidth="xs">
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" onClick={openForgotPassword} variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" onClick={goToSignUp} variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</form>
</div>
<Box mt={8}>
<Copyright />
</Box>
<ForgotPassword open={open} onClose={onClose} />
</Container>
);
}
export default SignIn;
Background is not getting dark with the type. Can someone help with this?

My bad. The latest version of Material UI now uses mode attribute of palette to determine whether dark mode or not. Simply change from 'type' to 'mode':
// Enabling Dark Mode according to system-wide setting
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = useMemo(
() => createMuiTheme({
palette: {
mode: prefersDarkMode ? 'dark' : 'light',
primary: purple,
secondary: green
},
}),
[prefersDarkMode],
);
Complete code of App.js:
import { createMuiTheme, CssBaseline, ThemeProvider, useMediaQuery } from "#material-ui/core";
import { green, purple } from "#material-ui/core/colors";
import { useEffect, useMemo } from "react";
import { Route, Switch, useHistory } from "react-router-dom";
import SignIn from "./ui/auth/SignIn.js";
import SignUp from "./ui/auth/SignUp.js";
import Welcome from "./ui/auth/Welcome.js";
const App = () => {
// Enabling Dark Mode according to system-wide setting
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = useMemo(
() => createMuiTheme({
palette: {
mode: prefersDarkMode ? 'dark' : 'light',
primary: purple,
secondary: green
},
}),
[prefersDarkMode],
);
const history = useHistory()
useEffect(() => {
// After displaying Welcome screen for 3 seconds
// go to SignIn page
const timer = setTimeout(() => {
history.push("/signin");
}, 3000);
return function cleanup() {
clearTimeout(timer);
};
});
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Switch>
<Route path="/" component={Welcome} exact />
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Switch>
</ThemeProvider>
);
}
export default App;

With the newer version of Material UI, you need to use createTheme and not createMuiTheme
https://material-ui.com/customization/palette/#user-preference
import React from 'react';
import useMediaQuery from '#material-ui/core/useMediaQuery';
import { createTheme, ThemeProvider } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
function App() {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = React.useMemo(
() =>
createTheme({
palette: {
type: prefersDarkMode ? 'dark' : 'light',
},
}),
[prefersDarkMode],
);
return (
<ThemeProvider theme={theme}>
<CssBaseline/>
<Routes />
</ThemeProvider>
);
}

Related

Material-UI theme remove after page refreash

I am facing a problem with my custom theme, whenever i refreshes my
page my custom theme for Tabs and Button in Navbar disappears,
sometime it doesn't even loads the Tabs and estimate button custom
theme.
Also in Header.js file code it says theme is not used but i am using
it in makeStyle function. (theme is declared on line-2 of Header.js).
Following are my code File:
Header.js
import React, {useState} from 'react'
import theme from "./Theme";
import { makeStyles } from '#mui/styles';
import {AppBar, Box, Button, Tab, Tabs, Typography, useScrollTrigger} from "#mui/material";
import {Toolbar} from "#mui/material";
import logo from '../../assets/logo.svg'
function ElevationScroll(props) {
const { children} = props;
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 0
});
return React.cloneElement(children, {
elevation: trigger ? 4 : 0,
});
}
const useStyles = makeStyles(theme=> ({
toolbarMargin: {
...theme.mixins.toolbar,
marginBottom:"3em"
},
companylogo:{
height:"7em"
},
tabName:{
marginLeft:"auto",
},
tab:{
...theme.typography.tab,
minWidth:10,
marginLeft:"25px",
color:"white"
},
estimateButton:{
...theme.typography.estimateButton,
height:"45px",
borderRadius:"25px",
marginLeft:"25px",
marginRight:"25px"
},
}))
function Navbar(){
const classes = useStyles();
const[value,setValue]=useState(0);
const handleChange=(e,value)=>
{
setValue(value);
}
return(
<React.Fragment>
<ElevationScroll>
<AppBar position={"fixed"}>
<Toolbar disableGutters={true}>
<img alt="company logo" className={classes.companylogo} src={logo} />
<Tabs className={classes.tabName} value={value} onChange={handleChange}>
<Tab className={classes.tab} label={"Home"}/>
<Tab className={classes.tab} label={"Services"}/>
<Tab className={classes.tab} label={"The Revolution"}/>
<Tab className={classes.tab} label={"About Us"}/>
<Tab className={classes.tab} label={"Contact Us"}/>
</Tabs>
<Button variant={"contained"} color={"secondary"} className={classes.estimateButton}>Free Estimate</Button>
</Toolbar>
</AppBar>
</ElevationScroll>
<div className={classes.toolbarMargin}/>
</React.Fragment>
);
}
export default Navbar;
Theme.js File:
import {createTheme} from "#mui/material/styles";
const arcBlue="#0B75B9";
const arcOrange="#FFA500";
const Theme = createTheme({
palette: {
primary: {
main: `${arcBlue}`
},
secondary: {
main: `${arcOrange}`
}
},
typography: {
tab:{
fontFamily:"Raleway",
fontWeight:1000,
fontSize:"1rem",
textTransform:"none",
color:"white"
},
estimateButton:{
fontFamily:"Raleway",
textTransform:"none",
fontWeight:700,
fontSize:"1rem",
height:"45px",
color:"white"
},
}
});
export default Theme;
App.js File:
import React from "react";
import Navbar from "../components/ui/header";
import {ThemeProvider} from "#mui/material/styles";
import theme from "./ui/Theme";
function App() {
return (
<>
<ThemeProvider theme={theme}>
<Navbar/>
</ThemeProvider>
</>
);
}
export default App;

MUI createTheme is not properly passing theme to MUI components

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

React-Native nested navigation not working in expo

I'm using the React Native Stack Navigation to configure the header in my app and then nest a Drawer Navigation inside of it.
In the android emulator, everything is working fine. But whenever I try to open the app using expo, there's nothing more then a white blank screen. Developer tools aren't logging any errors, Expo itself doesn't give me an error nor does the terminal.
I tried replacing the whole navigation with just a <Text> component and in this case Expo shows the text. But I can't seem to find what I'm doing wrong. Some help would be much appreciated since I'm just learning React Native.
This is my code:
index.tsx
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);
App.tsx
import React, {Component} from 'react';
import {NavigationContainer} from '#react-navigation/native';
import RootStack from './src/__plugins/navigation';
export default class App extends Component {
render() {
return (
<NavigationContainer>
<RootStack />
</NavigationContainer>
);
}
}
navigation/index.tsx
import {createStackNavigator} from '#react-navigation/stack';
import SignOutModalScreen from '../../_view/SignOutModalScreen';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {FontAwesomeIcon} from '#fortawesome/react-native-fontawesome';
import {faBars, faSignOutAlt, faTimes} from '#fortawesome/free-solid-svg-icons';
import {StyleSheet} from 'react-native';
import StartDrawer from './StartDrawer';
import {DrawerActions} from '#react-navigation/native';
export enum RoutingStack {
START = 'start',
GAME = 'main'
}
export enum RoutingDrawer {
START = 'start',
GAME = 'game'
}
export enum RoutingIdentifier {
JOIN_SCREEN = 'join',
GAME_SCREEN = 'game',
HELP_SCREEN = 'help',
SIGNOUT_SCREEN = 'sign_out'
}
const Stack = createStackNavigator();
const RootStack = () => {
return (
<Stack.Navigator
mode="modal"
screenOptions={({ navigation }) => ({
headerStyle: {
backgroundColor: '#80cbc4',
},
headerLeft: () => {
return (
<TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.toggleDrawer)}>
<FontAwesomeIcon icon={faBars} style={styles.menuIcon} />
</TouchableOpacity>
);
},
headerRight: () => {
return (
<TouchableOpacity onPress={() => navigation.navigate(RoutingIdentifier.SIGNOUT_SCREEN)}>
<FontAwesomeIcon icon={faSignOutAlt} style={styles.signOutIcon} />
</TouchableOpacity>
);
},
})}
>
<Stack.Screen
name={RoutingDrawer.START}
component={StartDrawer}
options={{ title: '' }}
/>
<Stack.Screen
name={RoutingIdentifier.SIGNOUT_SCREEN}
component={SignOutModalScreen}
options={({ navigation }) => ({
headerTitle: '',
headerStyle: {
elevation: 0,
backgroundColor: '#F5FCFF',
},
headerLeft: () => {
return (
<TouchableOpacity onPress={() => navigation.navigate(RoutingDrawer.START)}>
<FontAwesomeIcon icon={faTimes} style={styles.closeIcon} />
</TouchableOpacity>
);
},
})}
/>
</Stack.Navigator>
);
};
const styles = StyleSheet.create({
closeIcon: {
marginStart: 10,
color: 'black',
},
menuIcon: {
marginStart: 10,
color: 'white',
},
signOutIcon: {
marginEnd: 10,
color: 'white',
},
});
export default RootStack;
And the StartDrawer.tsx
import {createDrawerNavigator} from '#react-navigation/drawer';
import {RoutingIdentifier} from './index';
import JoinPage from '../../join/_view/JoinScreen';
import {FontAwesomeIcon} from '#fortawesome/react-native-fontawesome';
import {faQuestionCircle, faSignInAlt} from '#fortawesome/free-solid-svg-icons';
import {StyleSheet} from 'react-native';
import {trans} from '../i18n';
const Drawer = createDrawerNavigator();
const StartDrawer: FC = () => {
return (
<Drawer.Navigator drawerType="slide" hideStatusBar={false}>
<Drawer.Screen
name={RoutingIdentifier.JOIN_SCREEN}
component={JoinPage}
options={{
drawerLabel: trans.getString('MENU_START_GAME'),
drawerIcon: () => (
<FontAwesomeIcon icon={faSignInAlt} style={styles.icon} />
),
}}
/>
<Drawer.Screen
name={RoutingIdentifier.HELP_SCREEN}
component={() => null}
options={{
drawerLabel: trans.getString('MENU_HELP'),
drawerIcon: () => (
<FontAwesomeIcon icon={faQuestionCircle} style={styles.icon} />
),
}}
/>
</Drawer.Navigator>
);
};
const styles = StyleSheet.create({
icon: {
marginEnd: -20,
marginStart: 10,
},
});
export default StartDrawer;
I am not sure but have you tried the opposite? stack inside drawer instead of drawer inside of stack?
I have had good results with this. Perhaps my root navigator may help you. Try using it as a template (I have written this code some time ago so I don't remember specifics but it works well) :
import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { fetchPaymentMethods } from 'reducers/paymentMethods';
import { fetchNextPayments } from 'reducers/nextPayments';
import Home from 'pages/home';
import Orders from 'pages/orders';
import Settings from 'pages/settings';
import Scanner from 'pages/scanner';
import Support from 'pages/support';
import SideDrawer from 'components/SideDrawer';
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const StackNavigator = () => (
<Stack.Navigator headerMode="none">
<Stack.Screen name="Home" component={Home} />
<Drawer.Screen name="Orders" component={Orders} />
<Drawer.Screen name="Settings" component={Settings} />
<Drawer.Screen name="Scanner" component={Scanner} />
<Drawer.Screen name="Support" component={Support} />
</Stack.Navigator>
);
const RootNavigator = props => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchNextPayments());
dispatch(fetchPaymentMethods());
}, []);
return (
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Home"
screenOptions={{ gestureEnabled: true }}
drawerContent={props => <SideDrawer {...props} />}
>
<Drawer.Screen name="Root" component={StackNavigator} />
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Orders" component={Orders} />
<Drawer.Screen name="Settings" component={Settings} />
<Drawer.Screen name="Scanner" component={Scanner} />
<Drawer.Screen name="Support" component={Support} />
</Drawer.Navigator>
</NavigationContainer>
);
};
export default RootNavigator;

How to make theme state be persistent when visiting/reloading/or going back a page on the browser?

How can I get my light/dark theme to be persistently saved as a state when a user reloads, visits a new page, or presses back on a browser, etc... Right now it's very inconsistent.
Here is the index.js where I set up my theme. I wrap it around my components.
index.js
import { ThemeProvider, CssBaseline } from "#material-ui/core";
import { createMuiTheme } from "#material-ui/core";
const MyThemeContext = React.createContext({});
export function useMyThemeContext() {
return useContext(MyThemeContext);
}
function MyThemeProvider(props) {
const [isDarkMode, setIsDarkMode] = useState(false);
const theme = useMemo(
() =>
createMuiTheme({
palette: {
type: isDarkMode ? 'dark' : 'light',
},
}),
[isDarkMode]
);
return (
<ThemeProvider theme={theme}>
<MyThemeContext.Provider value={{ isDarkMode, setIsDarkMode }}>
{props.children}
</MyThemeContext.Provider>
</ThemeProvider>
);
}
const routing = (
<Router>
<React.StrictMode>
<MyThemeProvider>
<CssBaseline />
<Header />
<Switch>
<Route exact path="/" component={App} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
<Route path="/dash/:slug" component={Bucket} />
<Route path="/create" component={CreateBucket}/>
</Switch>
<Footer />
</MyThemeProvider>
</React.StrictMode>
</Router>
);
ReactDOM.render(routing, document.getElementById('root'));
I use a switch that activates the state of the theme, it's located in my header.
header.js
import React from 'react';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import CssBaseline from '#material-ui/core/CssBaseline';
import { makeStyles } from '#material-ui/core/styles';
import { NavLink } from 'react-router-dom';
import Link from '#material-ui/core/Link';
import Button from '#material-ui/core/Button';
import Switch from '#material-ui/core/Switch';
import { useMyThemeContext } from '../index';
const useStyles = makeStyles((theme) => ({
appBar: {
borderBottom: `1px solid ${theme.palette.divider}`,
},
link: {
margin: theme.spacing(1, 1.5),
},
toolbarTitle: {
flexGrow: 1,
},
}));
function Header() {
const classes = useStyles();
const {isDarkMode, setIsDarkMode} = useMyThemeContext();
return (
<React.Fragment>
<CssBaseline />
<AppBar
position="static"
color="default"
elevation={0}
className={classes.appBar}
>
<Toolbar className={classes.toolbar}>
<Switch
checked={isDarkMode}
onChange={() => setIsDarkMode(!isDarkMode)}
/>
</Toolbar>
</AppBar>
</React.Fragment>
);
}
export default Header;
How can I fix the inconsistency with the state not being saved? Thank you for the help!
you would use localStorage to persist state in memory, passing a key name. on app reload your initial state would come from that value stored in localStorage, if it's not set then !! will ensure the value is false rather than null
Also pass to Provider a function that updates state and also set the new value to localStorage. this way you don't need remember to set the value at localStorage every place you consume the setIsDarkMode
// if it's not set in localStorage value is null, then !! will set as false
const initialState = !!JSON.parse(localStorage.getItem('theme'))
function MyThemeProvider(props) {
const [isDarkMode, setIsDarkMode] = useState(initialState);
// you pass another function where you persist the value to localStorage
// given your code you may just create a toggle function where you don't need to pass a value. but you can change it to receive an argument
const toggleDarkMode = () => {
setIsDarkMode(themeMode => {
localStorage.setItem('theme', !themeMode)
return !themeMode
})
}
const theme = useMemo(
() =>
createMuiTheme({
palette: {
type: isDarkMode ? 'dark' : 'light',
},
}),
[isDarkMode]
);
return (
<ThemeProvider theme={theme}>
<MyThemeContext.Provider value={{ isDarkMode, toggleDarkMode }}>
{props.children}
</MyThemeContext.Provider>
</ThemeProvider>
);
}
and at your Header you extract toggleDarkMode instead:
function Header() {
const classes = useStyles();
const {isDarkMode, toggleDarkMode} = useMyThemeContext();
return (
<React.Fragment>
<CssBaseline />
<AppBar
position="static"
color="default"
elevation={0}
className={classes.appBar}
>
<Toolbar className={classes.toolbar}>
<Switch
checked={isDarkMode}
onChange={toggleDarkMode}
/>
</Toolbar>
</AppBar>
</React.Fragment>
);
}
export default Header;

How to set header zIndex?Getting below error:Cannot read property 'zIndex' of undefined

I am trying to keep my drawer component inside header by changing it's z-index but unable to do so as I am getting the error:Cannot read property 'zIndex' of undefined
Can anybody let me know where am I going wrong?
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Button from "#material-ui/core/Button";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import Drawer from '#material-ui/core/Drawer';
import CssBaseline from '#material-ui/core/CssBaseline';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import InboxIcon from '#material-ui/icons/MoveToInbox';
import MailIcon from '#material-ui/icons/Mail';
const drawerWidth = 240;
const styles = theme => ({
root: {
display: "flex",
justifyContent: "space-between"
},
appBar: {
zIndex:theme.zIndex.drawer + 1,
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
toolbar: theme.mixins.toolbar,
});
class Header extends Component {
render() {
return (
<div>
<AppBar position="static" style={styles.appBar}>
<Toolbar style={styles.root}>
<Typography color="inherit"> NEWS</Typography>
<Button color="inherit">LOGIN</Button>
</Toolbar>
<Drawer
style={styles.drawer}
variant="permanent"
style={{
paper: styles.drawerPaper,
}}
>
<div style={styles.toolbar} />
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
<List>
{['All mail', 'Trash', 'Spam'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
</AppBar>
</div>
);
}
}
export default Header;
I am trying to set zindex of appbar greater than the drawer z-index but it is not working
The issue with your code is that you cannot access the styles object until it is fully instantiated. What you probably want to do is to make styles a function which takes the theme as an argument and returns your styles object like so:
const styles = theme=>({
root: {
display: "flex",
justifyContent: "space-between"
},
appBar: {
zIndex:theme.zIndex.drawer + 1,
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
toolbar: theme.mixins.toolbar,
});
then export your Header component by wrapping it with the withStyles component wrapper and passing your styles to it like this.
export default withStyles(styles)(Header);
Here is the full code:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Button from "#material-ui/core/Button";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import Drawer from '#material-ui/core/Drawer';
import CssBaseline from '#material-ui/core/CssBaseline';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import InboxIcon from '#material-ui/icons/MoveToInbox';
import MailIcon from '#material-ui/icons/Mail';
const drawerWidth = 240;
const styles = theme => ({
root: {
display: "flex",
justifyContent: "space-between"
},
appBar: {
zIndex:theme.zIndex.drawer + 1,
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
toolbar: theme.mixins.toolbar,
});
class Header extends Component {
render() {
const {classes} = this.props;
return (
<div>
<AppBar position="static" className={classes.appBar}>
<Toolbar className={classes.root}>
<Typography color="inherit"> NEWS</Typography>
<Button color="inherit">LOGIN</Button>
</Toolbar>
<Drawer
className={classes.drawer}
variant="permanent"
style={{
paper: styles.drawerPaper,
}}
>
<div className={classes.toolbar} />
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
<List>
{['All mail', 'Trash', 'Spam'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
</AppBar>
</div>
);
}
}
export default withStyles(styles)(Header);
Note that these styles passed to your component with the withStyles wrapper is accessed with the classes props. You can then set a style to a component using the className property.

Categories

Resources