How To Install Material UI and Tailwind CSS In NextJS

Overview

In today’s world of web development, having a visually appealing and user-friendly website is crucial for success. Designers and developers often turn to popular front-end libraries such as Material UI and Tailwind CSS to achieve this. This blog will go through the steps of installing Material UI and Tailwind CSS into a Next.js project. With these tools at your disposal, you can easily create beautiful, responsive websites. So let’s get started!

Example code from GitHub. The Layout and Sign In page is built with MUI and other pages are Tailwind CSS examples.

Image Resource

Images for this example were taken from Lorem Picsum Photos.

Images are located under ‘.publicimages’

Github Repository with Solution

GitHub

Installing Material UI

MUI’s NextJS Template

If you are not using the source files above or don’t want to install the Material libraries manually, get the Next.js template from MUI.

https://github.com/mui/material-ui/tree/master/examples/nextjs

How to Install Material Manually

Configure Next.js with tsconfig.json

To add shortcuts for paths and other framework configurations, add a file labeled ‘.\tsconfig.json’ to the root of your NextJS project.

Example” The following configuration below lets you use ‘@\components\filename.js’ instead of ‘..\..\..\components\filename.js’ to import your components.

JSON source for tsconfig.json. For JavaScript only with no TypeScript label the file jsconfig.json.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
        "@/components/*": ["components/*"],
        "@/src/*": ["src/*"],
        "@/lib/*": ["lib/*"],
        "@/styles/*": ["styles/*"],
        "@/store/*": ["store/*"]
    },
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "incremental": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ] 
}

MUI – Material UI v5.4.3

Material UI library for React

Install the following libraries for Material.

npm install @mui/material @emotion/react @emotion/styled

Install the Material Icons library.

npm install @mui/icons-material

Adding a Material Theme

Create a folder labeled ‘./config’ and add a file labeled theme.js or theme.ts.

Source code for theme.js. Import this in App.tsx file or put the theme inside App.tsx and have a dark and light theme option.

import { Roboto } from '@next/font/google';
import { createTheme } from '@mui/material/styles';
import { red } from '@mui/material/colors';

export const roboto = Roboto({
  weight: ['300', '400', '500', '700'],
  subsets: ['latin'],
  display: 'swap',
  fallback: ['Helvetica', 'Arial', 'sans-serif'],
});

// Create a theme instance.
const theme = createTheme({
  palette: {
    primary: {
      main: '#556cd6',
    },
    secondary: {
      main: '#19857b',
    },
    error: {
      main: red.A400,
    },
  },
  typography: {
    fontFamily: roboto.style.fontFamily,
  },
});

export default theme;

Adding Emotion Cache

Add another file under ‘./config’ labeled createEmotionCache.js.

createCache allows for low level customization of how styles get inserted by emotion. It’s intended to be used with the <CacheProvider/> component to override the default cache. – (Excerpt from mui.com)

Code for createEmotionCache.js

import createCache from '@emotion/cache';

const isBrowser = typeof document !== 'undefined';

// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache() {
  let insertionPoint;

  if (isBrowser) {
    const emotionInsertionPoint = document.querySelector('meta[name="emotion-insertion-point"]');
    insertionPoint = emotionInsertionPoint ?? undefined;
  }

  return createCache({ key: 'mui-style', insertionPoint });
}

App.tsx

Source code for App.tsx

import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import * as React from 'react';
import Head from 'next/head';
import CssBaseline from '@mui/material/CssBaseline';
import { CacheProvider, EmotionCache } from '@emotion/react';
import { ThemeProvider } from '@mui/material/styles';
import createEmotionCache from '../config/createEmotionCache';
import theme from '../config/theme';

const clientSideEmotionCache = createEmotionCache();

interface MyAppProps extends AppProps {
  emotionCache?: EmotionCache;
}

export default function App(props: MyAppProps) {

  const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;

  return (
    <CacheProvider value={emotionCache}>
      <Head>
        <meta name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
        <CssBaseline />
        <Component {...pageProps} />
      </ThemeProvider>
    </CacheProvider>
  );
}

Next.config.js

next.config.js

+const withTM = require('next-transpile-modules')([
+  '@mui/material',
+  '@mui/system',
+  '@mui/icons-material', // If @mui/icons-material is being used
+]);

+module.exports = withTM({
 webpack: (config) => {
   config.resolve.alias = {
     ...config.resolve.alias,
+    '@mui/styled-engine': '@mui/styled-engine-sc',
    };
    return config;
  }
+});

If you are using TypeScript, you will need to also update the TSConfig.

tsconfig.json

 {
   "compilerOptions": {
+    "paths": {
+      "@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"]
+    }
   },
 }

If you are using TypeScript, you will need to also update the TSConfig.

client.js

import * as React from 'react';
import ReactDOM from 'react-dom';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import { CacheProvider } from '@emotion/react';
import App from './App';
import theme from './theme';
import createEmotionCache from './createEmotionCache';

const cache = createEmotionCache();

function Main() {
  return (
    <CacheProvider value={cache}>
      <ThemeProvider theme={theme}>
        {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
        <CssBaseline />
        <App />
      </ThemeProvider>
    </CacheProvider>
  );
}

ReactDOM.hydrate(<Main />, document.querySelector('#root'));

NextJS Configuration (Optional)

tsconfig.json – Configuration for folder locations under compilerOptions.

So you can use ‘@/components/’ instead of ‘../../components/’

Path definitions for ‘./component’, ‘./lib’, ‘./styles’, ‘./config’, ‘./store’ are for future uses of state management.

Configuration Code/JSON data for tsconfig.json.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
        "@/components/*": ["components/*"],
        "@/lib/*": ["lib/*"],
        "@/styles/*": ["styles/*"],
        "@/store/*": ["store/*"],
        "@/config/*": ["config/*"],        
    },
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "incremental": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"],
  "exclude": [
    "node_modules"
  ] 
}

Installing Tailwind CSS

Tailwind Libraries

CSS for the ImageCarousel.css file. The buttonBack and buttonNext style the plain out of the box next buttons so they look like transparent Fab buttons with an arrow symbol.

Pure-React-Carousel library. This library is structured so the developer can easily customize any component without trying to work around strict CSS or DOM rules.

npm install -D tailwindcss postcss autoprefixer

Additional Libraries for Tailwind Component Examples

Many of the examples from the Tailwind documentation will include the following libraries. The icons are a bit redundant since MUI has plenty of icons with @mui/icons-material.

Headless UI are libraries that give your Tailwind CSS code animation.

Hero Icons hand-crafted SVG icons if you don’t want to use MUI icons

npm install @heroicons/react @headlessui/react

Create Tailwind Configuration Files

The command below creates postcss.config.js and tailwind.config.js

npx tailwindcss init -p

Tailwind CSS Configuration File

Code for tailwind.config.js.

To avoid CSS styling overriding the Material Components, specify a path for all Tailwind CSS pages. For the most part you can mix the two but it might not always have the desired outcome. For instance a MUI button may loose the background color in a Tailwind page. You can however use a Tailwind button to open a MUI dialog box.

One strategy is to use .js or .ts for the pages and components that use Tailwind and .jsx and .tsx for those that use MUI.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [    
    "./app/**/*.{js,ts,jsx,tsx}",
    "./pages/tw/**/*.{js,ts,jsx,tsx}",
    "./components/tw/**/*.{js,ts,jsx,tsx}",   
    // Or if using `src` directory:
    "./src/**/*.{js,ts,jsx,tsx}",  
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Adding Tailwind Directives to Global CSS File

Create a file labeled global.css under ‘./styles/’.

Adding Tailwind Style to Whole Project

Add the following to global.css directives for tailwind css.

@tailwind base;
@tailwind components;
@tailwind utilities;

Adding Tailwind To Specific Pages

There will be cases where you do want to override the Tailwinddirectives in your global.css file. Some 3rd party libraries such as carousels or image magnifiers may have issues rendering.

Solution

Do not add Tailwinddirectives to global.css

Instead add the following import to the individual pages that are using Tailwind.

import "tailwindcss/tailwind.css";

Test Tailwind

Code for ‘./pages/tw/index.js

export default function Home() {
  return (
    <h1 className="text-3xl font-bold underline">
      Hello world!
    </h1>
  )
}

Conclusion

In conclusion, adding Material UI and Tailwind CSS to a Next.js project can significantly enhance your website’s visual appeal and user experience. The installation process is straightforward and can be easily accomplished with the steps outlined in this blog. With these powerful front-end libraries at your disposal, you now have the tools to create beautiful and responsive websites that stand out from the crowd. So, start incorporating Material UI and Tailwind CSS into your Next.js projects and take your web development to the next level!.