How to Style MUI Components with TailwindCSS inside a NextJS Project
Jasser Mark Arioste
Hello, hustlers! In this tutorial, you'll learn how to style MUI Components using TailwindCSS Classes inside a NextJS project.
Introduction #
MUI is a popular library of React components, TailwindCSS is a popular choice for styling components, and NextJS is a very popular choice for a React framework. Wouldn't it be great if we could integrate these technologies together?
Final Output #
Here's the final output. A switch component styled using TailwindCSS classes.
Tutorial Objectives #
- Learn how to Setup MUI and TailwindCSS in NextJS
- Create a component from
@mui/base
library so that it's styled with TailwindCSS instead of the default.
Step 1 - NextJS with MUI #
First, we'll have to set up MUI with NextJS, then we'll install TailwindCSS afterward. I already created a previous tutorial on how to set up MUI with NextJS so we'll continue from that tutorial. I suggest you do the previous tutorial and then continue to Step 2 of this tutorial.
Or, if you want to skip the previous tutorial, we can use the code from the previous tutorial as a NextJS starter template. Run the following command and this will give you a NextJS project with MUI pre-installed:
npx create-next-app -e https://github.com/jmarioste/nextjs-mui-typescript-starter my-project
Step 2 - Installing TailwindCSS #
Next, let's install TailwindCSS into our project. Run the following commands to install the prerequisites and initialize tailwind:
# terminal
yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
After this step, you should see the tailwind.config.js
file in your root project directory.
Step 3 - Modifying tailwind.config.js
#
Next, we need to modify the tailwind.config.js
file for MUI and TailwindCSS to work correctly. You can read more about it here in the MUI documentation. Copy the code below to your tailwind.config.js
file.
// tailwind.config.js /** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./app/**/*.{js,ts,jsx,tsx,mdx}", "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", // Or if using `src` directory: "./src/**/*.{js,ts,jsx,tsx,mdx}", ], corePlugins: { preflight: false, }, important: "#__next", theme: { extend: {}, }, plugins: [], };
1234567891011121314151617181920
Step 4 - Modifying styles/globals.css
#
Next, let's modify globals.css
so that it includes the tailwind classes.
// styles/globals.css @tailwind base; @tailwind components; @tailwind utilities;
1234
After this, we should be able to use TailwindCSS for MUI components.
Step 5 - Installing @mui/base
package
#
Next, let's install the @mui/base
package so that we'll have access to MUI's unstyled components. This way, we'll have complete control over the styling of these components.
yarn add @mui/base
All the base MUI components are available on mui.com/base.
Step 6 - Creating a Custom Switch Component #
For this tutorial, we'll create a custom <Switch/>
Component. First, let's create a completely unstyled switch component. Start by creating the file, src/compnents/MySwitch.tsx
:
import { SwitchUnstyled, SwitchUnstyledProps } from "@mui/base"; const MySwitch = (props: SwitchUnstyledProps) => { return ( <> <SwitchUnstyled {...props} // available elements inside SwitchUnstyled that we can style slotProps={{ root(state) {}, input(state){}, thumb(state){}, track(state){}, }} /> </> ); }; export default MySwitch;
12345678910111213141516171819
Explanation:
We are using the SwitchUnstyled
component. The slotProps
property lets us know which elements we can style. For the switch component, we can style the following: root
, input
, thumb
, and track
. If we check the rendered output it renders these 4 elements in the HTML document:
Next, let's style all these elements one by one.
Step 7 - Styling the root
slot/element
#
First, let's install a utility package called classnames
. This will help us toggle tailwind CSS classes depending on the state of the component. Run the command below:
yarn add classnames
For the root element, we'll define some basic properties such as the height and width of the switch. We'll also tone down the opacity to 40% if the state is disabled. We use the classnames
package to toggle the opacity.
// src/components/MySwitch.tsx import { SwitchUnstyled, SwitchUnstyledProps } from "@mui/base"; import classNames from "classnames"; const MySwitch = (props: SwitchUnstyledProps) => { return ( <> <SwitchUnstyled {...props} // slotProps = available elements inside SwitchUnstyled that we can style slotProps={{ root(state) { return { className: classNames({ "inline-block relative w-10 h-6 rounded-lg m-2": true, "opacity-[40%] cursor-not-allowed": state.disabled, }), }; }, }} /> </> ); }; export default MySwitch;
12345678910111213141516171819202122232425
Step 8 - Styling the thumb
slot/element
#
The thumb element is the small element that moves left and right if the switch is checked or not.
const MySwitch = (props: SwitchUnstyledProps) => { return ( <> <SwitchUnstyled {...props} // slotProps = available elements inside SwitchUnstyled that we can style slotProps={{ ... thumb(state) { return { className: classNames({ "absolute block w-4 h-4 rounded-sm top-[4px] left-[4px] transition-all duration-150 ease-in-out bg-white": true, "translate-x-4": state.checked, }), }; }, }} /> </> ); }; export default MySwitch;
1234567891011121314151617181920212223
Step 9 - Styling the input
slot/element
#
Next, let's style the input
element. The input element is of type "checkbox" by default so we'll have to hide that so that it doesn't show to the user.
const MySwitch = (props: SwitchUnstyledProps) => { return ( <> <SwitchUnstyled {...props} // slotProps = available elements inside SwitchUnstyled that we can style slotProps={{ //... input(state) { return { className: classNames({ "absolute w-full h-full z-[1] top-0 left-0 opacity-0 margin-0": true, "cursor-pointer": !state.disabled, "cursor-not-allowed": state.disabled, }), }; }, }} /> </> ); }; export default MySwitch;
123456789101112131415161718192021222324
Step 10 - Styling the track
slot/element.
#
Next, let's style the track slot. This is the blue/gray background of the switch component.
import { SwitchUnstyled, SwitchUnstyledProps } from "@mui/base"; import classNames from "classnames"; const MySwitch = (props: SwitchUnstyledProps) => { return ( <> <SwitchUnstyled {...props} // slotProps = available elements inside SwitchUnstyled that we can style slotProps={{ //... track(state) { return { className: classNames({ "w-full h-full block rounded-sm": true, "bg-indigo-500": state.checked, "bg-gray-500": !state.checked, }), }; }, }} /> </> ); }; export default MySwitch;
1234567891011121314151617181920212223242526
Step 11 - Demo #
Now it's time for some demos. First, let's render our <Switch/> components in pages/index.tsx
:
// pages/index.tsx import type { NextPage } from "next"; import MySwitch from "../src/components/MyButton"; const Home: NextPage = () => { return ( <div className="container mx-auto"> <MySwitch /> <MySwitch defaultChecked /> <MySwitch disabled /> <MySwitch defaultChecked disabled /> </div> ); }; export default Home;
12345678910111213141516
Here's the output:
That's basically it!
Full Code #
The full code is available at GitHub: jmarioste/nextjs-mui-tailwindcss-typescript-starter
Conclusion #
You learned how to set up MUI with TailwindCSS and NextJS. More importantly, you learned how to use unstyled MUI components and style the respective elements inside them with TailwindCSS classes.
If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on GitHub.
Resources #
Credits: Image by Roger Sexton from Pixabay