How to use Material UI's ThemeProvider with next.js? - reactjs

I want to pallete of the theme for my next.js app.
I'm very new to next.js so please be kind. I can give more info if something specific is required.
This is my index.js
import Navbar from "../src/components/navbar";
import Frontpage from "../src/components/frontpage ";
import { Grid, ThemeProvider, createMuiTheme } from "#material-ui/core";
const theme = createMuiTheme({
pallete: {
primary: {
main: '#abcdef',
}
}
})
function Index() {
return (
<ThemeProvider theme={theme}>
<Grid container justify="center" style={{ scrollBehavior: "smooth" }}>
<Grid item xs={9}>
<Navbar />
<Frontpage />
</Grid>
</Grid>
</ThemeProvider>
);
}
export default Index;
This is my Frontpage.js
import Grid from "#material-ui/core/Grid";
import { Button } from "#material-ui/core";
import styles from "../styles/_homeview.module.scss";
const Frontpage = () => {
return (
<>
<Grid item className={styles.homehead}>
Heading 1
</Grid>
<Grid item xs={6} className={styles.homeTagLine}>
lorem ipsum for, lets say around 30 words
</Grid>
<Button variant="contained" color="primary">
Contact Us
</Button>
</>
);
};
export default Frontpage;
Here I expect the button to be of color specified in the theme (#abcdef) but its the default Material UI theme color.
How can I fix (apply/modify) the default Material UI theme?

There is a typo - palette not pallete in your example!
const theme = createMuiTheme({
palette: {
primary: {
main: '#abcdef',
}
}
})

Related

React Mui Appbar theming

I tried theming MUI AppBar but I have no idea about theming.
Can I style an AppBar with theme without using styled component or other style api?
palette.js
import { createTheme } from '#mui/material/styles';
const theme = createTheme({
palette: {
primary: {
main: "#000F04"
}
}
});
App.js
import theme from "../../styles/palette";
import { ThemeProvider } from '#mui/material/styles';
const App = () => {
return (
<ThemeProvider theme={theme}>
<AppBar position="static" color="primary">
<Toolbar>
</Toolbar>
</AppBar>
</ThemeProvider>
)
}
Your codesandbox work.
Use the sx props if you need to add specific style. https://mui.com/system/the-sx-prop/
You can too overide style on the theme: https://mui.com/customization/theme-components/#heading-global-style-overrides

useState not working in next js with material ui drawer

useState not working. I have searched for a solution I checked many forms like https://github.com/vercel/next.js/issues/7626 , https://github.com/vercel/next.js/issues/17592 ,
Hooks error: Invalid Hook Call using NextJS or ReactJS on Windows , some people seem to suggest that it can be solved by removing a node module that they did not mention the name of, others says it works if they change their webpack configurations but i have never used webpack and couldn't find they mentioned so I am stuck.
I was implementing material ui's drawer, i have created a drawer component and imported it.
Nav.jsx:
import React, { useState } from 'React'
import SignedOutLinks from "./Links/SignedOutLinks"
import { AppBar, Toolbar } from "#material-ui/core"
import MenuBtn from "./Links/MenuBtn"
import Logo from "./Links/Logo"
import CategoryBtn from "./Links/CategoryBtn"
import ShoppingCartBtn from "./Links/ShoppingCartBtn"
import LanguageBtn from "./Links/LanguageBtn"
import DarkModeBtn from "./Links/DarkModeBtn"
import NotificationBtn from "./Links/NotificationBtn"
import SignedIn from "./Links/SignedIn"
import Grid from '#material-ui/core/Grid';
import Search from "./Search/Search"
import { useTheme } from '#material-ui/core/styles';
import useMediaQuery from '#material-ui/core/useMediaQuery';
import Drawer from './Drawer/Drawer'
const signedIn = true
const Nav = () => {
const [isOpened, setIsOpened] = useState(false)
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down("sm"))
const handleDrawerToggle = () => {
setIsOpened(!isOpened)
}
return (
<AppBar color="transparent" elevation={0} >
<Toolbar>
{
!isMobile?
<Grid
container
direction="row"
justify="space-between"
alignItems="center"
spacing={10}
>
<Grid item container spacing={5} xs={4} justify="flex-start" wrap="nowrap">
<Grid item>
<Logo/>
</Grid>
<Grid item>
<CategoryBtn />
</Grid>
</Grid>
<Grid item xs={4}>
<Search />
</Grid>
<Grid item container xs={4} justify="flex-end" wrap="nowrap">
<ShoppingCartBtn />
<LanguageBtn />
<DarkModeBtn />
<NotificationBtn />
{signedIn? <SignedIn /> : <SignedOutLinks />}
</Grid>
</Grid>
:
<div>
<Drawer isOpened={isOpened} />
<Grid
container
direction="row"
justify="space-around"
spacing={10}
>
<Grid item container xs={4} justify="flex-start">
<MenuBtn handleClick={handleDrawerToggle} />
</Grid>
<Grid item Container xs={4} justify="center" style={{textAlign: "center"}}>
<Grid item>
<Logo />
</Grid>
</Grid>
<Grid item container xs={4} justify="flex-end">
<ShoppingCartBtn />
</Grid>
</Grid>
</div>
}
</Toolbar>
</AppBar>
)
}
export default Nav
Drawer.jsx:
import { Drawer as MUIDrawer} from '#material-ui/core'
import { List, ListItem,ListItemText, ListItemIcon } from '#material-ui/core'
import NotificationsIcon from '#material-ui/icons/Notifications';
import TranslateIcon from '#material-ui/icons/Translate';
import Brightness4Icon from '#material-ui/icons/Brightness4';
import LocalShippingIcon from '#material-ui/icons/LocalShipping';
import AccountCircleIcon from '#material-ui/icons/AccountCircle';
import BusinessIcon from '#material-ui/icons/Business';
import ExitToAppIcon from '#material-ui/icons/ExitToApp';
import ChatBubbleOutlineIcon from '#material-ui/icons/ChatBubbleOutline';
import CategoryIcon from '#material-ui/icons/Category';
function Drawer({isOpened}) {
const items = [
{
text: user.userName,
icon: <AccountCircleIcon />
},
{
text: "Categories",
icon: <CategoryIcon />
},
{
text: "Language",
icon: <TranslateIcon />
},
{
text: "Mode",
icon: <Brightness4Icon />
},
{
text: "Notifications",
icon: <NotificationsIcon />
},
{
text: "Orders",
icon: <LocalShippingIcon />
},
{
text: "Are You a Seller?",
icon: <BusinessIcon />
},
{
text: "Messages",
icon: <ChatBubbleOutlineIcon />
},
{
text: "Logout",
icon: <ExitToAppIcon />
}
]
return (
<div>
<MUIDrawer open={isOpened}>
<List>
{
items.map(item => {
return (
<ListItem button key={item.text} >
{item.icon && <ListItemIcon>{item.icon}</ListItemIcon>}
<ListItemText primary={item.text} />
</ListItem>
)
})
}
</List>
</MUIDrawer>
</div>
)
}
export default Drawer
Note it was working fine until i coded the Drawer, also useState is imported at the very beginning ing so i didn't forget to import it
Edit:
Folder Structure in next.js
index.js:
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import Nav from '../Components/Navbar/Nav'
export default function Home() {
return (
<>
<Head>
<meta name="description" content="Everything for everyone. TRNC E-commerce website focused on a huge variety of categories from fashion to electronics. Order now and get your product delivered." />
</Head>
<div className={styles.container}>
<Nav />
</div>
</>
)
}
Its finally working, however I couldn't find the problem. I solved it by literaly creating a new component called Nav2 that i copied the same code from the original Nav component from and voila it worked, i deleted the old Nav component and renamed Nav2 to Nav and it kept working.
Note: i found that i forgot to import useContext in the drawer as user is an deconstructed object that is sent from _app.js so i added
const { user } = useContext(UserContext)
to the beginning of the component function

Material-UI ThemeProvider not passing theme to components

I've created a theme in my App.js which overrides the Primary and Secondary color. I have ThemeProvider wrapping a Home component. The overridden values are not showing up in the Home component. What am I doing wrong?
App.js
import React from 'react'
import { ThemeProvider, createMuiTheme } from '#material-ui/core/styles'
import purple from '#material-ui/core/colors/purple'
import green from '#material-ui/core/colors/green'
import Home from './components/Home'
const theme = createMuiTheme({
overrides: {
pallete: {
primary: {
main: purple[500]
},
secondary: {
main: green[500]
}
}
}
})
const App = () => {
return (
<ThemeProvider theme={theme}>
<Home />
</ThemeProvider>
)
}
export default App
Home.js
import React from 'react'
import { useTheme } from '#material-ui/core/styles'
import { Container, Grid, AppBar, Toolbar, CssBaseline } from '#material-ui/core'
const Home = () => {
const theme = useTheme()
return (
<Container max="lg">
<CssBaseline />
<Grid container>
<Grid item xs={12}>
<AppBar color="primary">
<Toolbar>
Hello World
</Toolbar>
</AppBar>
</Grid>
</Grid >
</Container >
)
}
export default Home
I would think that in my AppBar the color="primary" should show up with the overridden primary color. But it's not happening.
You've got some typo (like pallete instead of palette, redundant overrides prop etc).
Here a working example.

Am I on the right track with my Material UI AppBar?

I'm working on a header for my site, and want to use Material UI. The header includes a logo, some nav links, an avatar with dropdown, etc. My question revolves around styling the nav links right now. With Material-UI, do I need to apply classes to /every/ element I want to style? For example, I currently have an app that looks like this:
import React from 'react';
import AppBar from '#material-ui/core/AppBar';
import Avatar from '#material-ui/core/Avatar';
import CssBaseline from '#material-ui/core/CssBaseline';
import IconButton from '#material-ui/core/IconButton';
import Link from '#material-ui/core/Link';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import theme from './theme';
import { ThemeProvider } from '#material-ui/core/styles';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles(theme => ({
root: {
backgroundColor: '#202632',
},
headerLink: {
padding: '10px 20px',
}
}));
function App() {
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const classes = useStyles();
return (
<div className="App">
<ThemeProvider theme={theme}>
<CssBaseline />
<AppBar className={classes.root}>
<Toolbar className={classes.logo}>
<img alt="Logo" src="/logo2.png" height={60} />
<Link className={classes.headerLink} href="/dashboard">
Solutions
</Link>
<Link className={classes.headerLink} href="/clientportal">
Features
</Link>
<Link className={classes.headerLink} href="/pricing">
Pricing
</Link>
<Link className={classes.headerLink}>
Our team
</Link>
<Link className={classes.headerLink}>
Blog
</Link>
<Avatar onClick={handleClick} onClose={handleClose}>
DM
</Avatar>
<Menu anchorEl={anchorEl} open={Boolean(anchorEl)}>
<MenuItem onClick={handleClose}>Item1</MenuItem>
<MenuItem onClick={handleClose}>Item2</MenuItem>
<MenuItem onClick={handleClose}>Item3</MenuItem>
</Menu>
</Toolbar>
</AppBar>
</ThemeProvider>
</div>
);
}
export default App;
The typical way I would style links is with CSS, using something like nav a { padding: 20px }, however that doesn't appear to be the idiomatic way with Material-UI. Maybe I have that assumption wrong so I wanted to verify here what the best approach for styling overrides looks like.
Thanks
You could create a SFC for the Link.
import React from ‘react’;
import Link from '#material-ui/core/Link';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles(theme => ({
headerLink: {
padding: '10px 20px',
}
}));
const AppBarLink = React.forwardRef(function AppBarLink({ children, className, ...props }, ref) {
const classes = useStyles();
return (
<Link
className={`${classes.headerLink} ${className}`}
ref={ref}
{...props}
>
{children}
</Link>
);
});
export AppBarLink;
For this particular scenario, I would use withStyles to create a styled version of Link. This will have the same effect as psyrendust's answer, but using withStyles gets rid of all the boilerplate.
import React from ‘react’;
import Link from '#material-ui/core/Link';
import { withStyles } from '#material-ui/core/styles';
const AppBarLink = withStyles({
root: {
padding: '10px 20px'
}
})(Link);
export AppBarLink;
Putting this in its own file and exporting it is only necessary if you want to leverage it from multiple files. If you are only using it in one file, then just define it there.
If you want to control props in addition to styles, you can leverage defaultProps as shown in the working example below:
import React from "react";
import Link from "#material-ui/core/Link";
import { withStyles } from "#material-ui/core/styles";
const AppBarLink = withStyles({
root: {
padding: "10px 20px"
}
})(Link);
AppBarLink.defaultProps = {
color: "secondary"
};
export default function App() {
return (
<div className="App">
<Link>Here is Link (no padding or color override)</Link>
<br />
<AppBarLink>Here is AppBarLink</AppBarLink>
<br />
<AppBarLink color="primary">
Here is AppBarLink with explicit color of primary
</AppBarLink>
</div>
);
}

Which React Material-UI components add a spacing to my page (like a row class in Bootstrap)?

I've created a project using React and Material-UI for React.
Coming from a Bootstrap background, I've noticed none of these components come with any margin around their components.
In Bootstrap I can add spacing like this:
<div class="row">
<div class="col-xs-12">
...
</div>
</div>
But I've got no idea what component to use to create such spacing.
I'm currently using custom classes to create some sort of spacing, but it doesn't feel correct.
App.tsx:
<Container maxWidth="lg" className="container-padding">
...
</Container>
App.css:
.container-padding {
padding: 30px;
}
For example, add spacing between these elements with an existing component:
I'm open for suggestions.
There is a grid layout component in #material-ui similar to Bootstrap grid. Both are based on a 12-column grid.
The below example demonstrates it,
import Box from '#material-ui/core/Box';
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
return (
<Box m={4}>
<Grid container spacing={3}>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item xs={6}>
<Paper>xs=6</Paper>
</Grid>
<Grid item xs={3}>
<Paper>xs=3</Paper>
</Grid>
<Grid item xs={3}>
<Paper>xs=3</Paper>
</Grid>
<Grid item xs={3}>
<Paper>xs=3</Paper>
</Grid>
<Grid item xs={3}>
<Paper>xs=3</Paper>
</Grid>
</Grid>
</Box>
<Box mx={3}>
Box 2 content
</Box>
<Box my={3}>
Box 3 content
</Box>
);
So to summarize,
m - all sides margin
mx - Horizontal spacing
my - Vertical spacing
I've used the "Lobotomized Owl" selector by Heydon Pickering: * + *.
I created a 'container' component Vertical.js:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { Box } from '#material-ui/core';
const useStyles = makeStyles((theme) => ({
vertical: {
'& > *+*': {
marginTop: '1.5rem',
},
},
}));
const Vertical = ({ children }) => {
const classes = useStyles();
return <Box className={classes.vertical}>{children}</Box>;
};
export default Vertical;
Then use it in any other components e.g. Example.js:
import React from 'react';
import Vertical from './Vertical';
const Example = () => {
return (
<Vertical>
<Component/>
<Component />
<Another />
<AnotherComponent />
</Vertical>
);
};
export default Example;

Resources