Next.js is a convenient and powerful framework for React. Its main benefit over using React directly is its transparent support for Server-Side Rendering.
Material UI is a very popular set of React components implementing Google’s Material Design guidelines.
Both libraries are impressive, but there are some tricks to know to make them playing well together.
Bootstrapping
Setting up MUI in a Next project requires some non-trivial tweaks to Next’s initialization process. Conveniently, Material UI provides a skeleton containing a working Next.js project with Material UI already properly configured. It’s the easiest way to kickstart a new project using both tools, don’t miss it!
# Download the skeleton
$ curl https://codeload.github.com/mui-org/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/nextjs
$ cd nextjs
# Install the deps
$ yarn install
# Start the project
$ yarn dev
To learn how to integrate Material UI in an existing project, take a look to pages/_document.js
and pages/_app.js
they contain most the wiring logic.
Forms
Material UI is especially useful because of the large set of form components it provides. But handling forms with React (and so with Next) is tedious and verbose. My colleague Morgan Auchedé recently told me about Formik. Formik is a tiny yet super powerful library allowing to easily create forms with React. And good news: it plays very well with Next! Here is how a basic login form looks when using Formik:
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
export default MyForm = () => (
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
// Your client-side validation logic
}}
onSubmit={(values, { setSubmitting }) => {
// Call your API
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" />
<Field type="password" name="password" />
<ErrorMessage name="password" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
Nice! However, when switching to Material UI inputs, the high level helper components provided by Formik become almost useless. Our forms are verbose again. Fortunately, a small library intuitively named
makes it easy to bridge both libraries! Here is the same form as before (including error handling), but rendered using Material UI components:formik-material-ui
import React from 'react';
import { Formik, Form, Field } from 'formik';
import { TextField } from 'formik-material-ui';
import Button from "@material-ui/core/Button";
export default MyForm = () => (
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
// Your client-side validation logic
}}
onSubmit={(values, { setSubmitting }) => {
// Call your API
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" component="TextField" />
<Field type="password" name="password" component="TextField" />
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
disabled={isSubmitting}
>
Submit
</Button>
</Form>
)}
</Formik>
);
This form is even less verbose, and is now looking good!
Buttons and Routing
Next.js comes with a nice routing system working transparently regardless if the app is executed client-side or server-side. It’s one of the biggest strength of the framework. However, in Material UI, the Button component is often used to trigger navigation between pages, and using buttons with the Router isn’t very intuitive. Still, it’s easy to do:
import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Button";
export default MyLink = () => (
<Link href="/pricing" passHref>
<Button component="a">Managed version</Button>
</Link>
);
First, we set the component
prop of Button
to a
. It tells Material UI to use an anchor for this button, instead of a… button
by default. Then, we set the passHref
prop of the Link
element, it hints the Router to pass the href
prop to the child component, even if doesn’t look like an anchor. Actually (because of the component
prop we set earlier), the grandchild will be an anchor, and Material UI will forward the href
prop to it! The rendered a
element now has a proper href
attribute, both client-side and in the server-side generated HTML. Good SEO, for free!
The same trick can be used with the Typography component:
import React from "react";
import Link from "next/link";
import Button from "@material-ui/core/Typography";
export default MyLink = () => (
<Link href="/pricing" passHref>
<Typography variant="caption" component="a">Managed version</Typography>
</Link>
);
This time, we created a link looking like a caption!
That’s all for today. Have fun with Next and Material UI! For more tricks about JavaScript (among various other technologies), follow me on Twitter!
Great article! Thank you
this looks real promising
I’m getting the warning: : is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
additionally I cannot see the email or password text fields.
I was having the same error and ended up following the examples on FormLink Material UI I think the fix iis just to review that the import for TextField needs to come from:
import {TextField} from ‘formik-material-ui’;
https://stackworx.github.io/formik-material-ui/docs/api/material-ui