Skip to content

Kévin Dunglas

Founder of Les-Tilleuls.coop (worker-owned cooperative). Creator of API Platform, FrankenPHP, Mercure.rocks, Vulcain.rocks and of some Symfony components.

Menu
  • Talks
  • Resume
  • Sponsor me
  • Contact
Menu

Using Next.js and Material UI Together

Posted on May 26, 2019May 27, 2019 by Kévin Dunglas

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 formik-material-ui makes it easy to bridge both libraries! Here is the same form as before (including error handling), but rendered using Material UI components:

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!

Related posts:

  1. React ESI: Blazing Fast SSR
  2. API Platform Admin 0.2: an admin in 1 minute for your API (React Progressive Web App)
  3. API Platform and Symfony: a Framework for API-driven Projects (SymfonyCon)
  4. API Platform 2.1: when Symfony meets ReactJS (Symfony Live)

4 thoughts on “Using Next.js and Material UI Together”

  1. Cortisse Arnaud says:
    January 17, 2020 at 9:33 am

    Great article! Thank you

    Reply
  2. Joshua Andrew Jourdain says:
    February 12, 2020 at 12:30 pm

    this looks real promising

    Reply
    1. Joshua Andrew Jourdain says:
      February 13, 2020 at 7:06 pm

      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.

      Reply
      1. Fernando Lee says:
        April 15, 2020 at 10:32 pm

        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

        Reply

Leave a ReplyCancel reply

Social

  • Bluesky
  • GitHub
  • LinkedIn
  • Mastodon
  • X
  • YouTube

Links

  • API Platform
  • FrankenPHP
  • Les-Tilleuls.coop
  • Mercure.rocks
  • Vulcain.rocks

Subscribe to this blog

Top Posts & Pages

  • Symfony's New Native Docker Support (Symfony World)
  • JSON Columns and Doctrine DBAL 3 Upgrade
  • Securely Access Private Git Repositories and Composer Packages in Docker Builds
  • Develop Faster With FrankenPHP
  • Preventing CORS Preflight Requests Using Content Negotiation
  • FrankenPHP: The Modern Php App Server, written in Go
  • Generate a Symfony password hash from the command line
  • PHP and Symfony Apps As Standalone Binaries
  • How to debug Xdebug... or any other weird bug in PHP
  • Running Laravel Apps With FrankenPHP (Laracon EU)

Tags

Apache API API Platform Buzz Caddy Docker Doctrine FrankenPHP Go Google GraphQL HTTP/2 Hydra hypermedia Hébergement Javascript JSON-LD Kubernetes La Coopérative des Tilleuls Les-Tilleuls.coop Lille Linux Mac Mercure Mercure.rocks Messagerie Instantanée MySQL performance PHP Punk Rock Python React REST Rock'n'Roll Schema.org Security SEO SEO Symfony Symfony Live Sécurité Ubuntu Web 2.0 webperf XML

Archives

Categories

  • DevOps (84)
    • Ubuntu (68)
  • Go (17)
  • JavaScript (46)
  • Mercure (7)
  • Opinions (91)
  • PHP (170)
    • API Platform (77)
    • FrankenPHP (9)
    • Laravel (1)
    • Symfony (97)
    • Wordpress (6)
  • Python (14)
  • Security (15)
  • SEO (25)
  • Talks (46)
© 2025 Kévin Dunglas | Powered by Minimalist Blog WordPress Theme