Twin Macro
TailwindCSS and Material-UI(MUI) for a React Application.
Question: How do you combine the TailwindCSS theme with Material-UI in an Application? In other words, how do I make MUI theme work with TailwindCSS classes?
Answer: Twin Macro; I will be using a Vite React TypeScript Application to illustrate how to combine styling themes (TailwindCSS and Material-UI). This is very useful for large projects where you want to ensure there is synergy in styling themes and that patterns are reusable.
Definitions:
Twin Macro is a library that makes TailwindCSS able to work with other CSS-in-JS libraries such as styled-component, and Emotion. With this library, you have a wider range of styling capabilities.
TailwindCSS: is a styling library that uses utility first styling this means styling is done as class names. It’s a direct styling and handles mobile and web views. With TailwindCSS, there is no need for external CSS classes and Ids, you can build a complete custom design without ever leaving your HTML.
Material-UI: is a popular React UI library that offers different design components to create a user interface in applications. These components already exist and developers do not have to build them from scratch.
Vite: It’s just blazingly fast for Front-end development. See the article for the Vite setup. You can find Vite starter packages in Docs
Setup TailwindCSS
Installing TailwindCSS is very simple and direct. See Docs
- Install TailwindCSS as a dev dependency
yarn add -D tailwindcss postcss autoprefixer
ornpm install -D tailwindcss postcss autoprefixer
- Run
npx tailwindcss init -p
to generate tailwind.config.js and postcss.config.js files. If your file is in commonjs(.cjs), you can rename it to .js and remove the type: “module” on the package.json file. - Add the paths to files and configure your styling settings in the tailwind.config.js file. As shown below,
/** @type {import(‘tailwindcss’).Config} */
module.exports = {
mode: “jit”,
content: [“./src/**/*.{ts,tsx}”, “./components/**/*.{ts,tsx}”],
theme: {
extend: {
colors: {
primary: “hsla(120, 100% ,25%,1)”,
secondary: “hsla(330, 100% ,71%,1)”,
},
},
},
plugins: [],
};
4. Add the Tailwind directives to the App global CSS file. You could add this to your App.css file
//App.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Setup Material-UI
1) Install MUI libraries. See docs yarn add @mui/material @emotion/react @emotion/styled
ornpm install @mui/material @emotion/react @emotion/styled
2) Create a theme.tsx file in the src folder and add the following,
// theme.tsx file
import { createTheme } from “@mui/material/styles”;
const theme = createTheme({});
export default theme;
- Add MUI Theme Provider context to the App global file(main.tsx) as follow:
// main.tsx
import React from “react”;
import ReactDOM from “react-dom/client”;
import App from “./App”;
import { ThemeProvider } from “@mui/material”;
import theme from “./theme”;
ReactDOM.createRoot(document.getElementById(“root”)
as HTMLElement).render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</React.StrictMode>
);
Setup Twin Macro
1) To Install the Twin Macro package, see the docs example alsoyarn add twin.macro
or npm install twin.macro
2) Install babel-plugins to support styling
yarn add babel-plugin-macros @emotion/babel-plugin-jsx-pragmatic @babel/plugin-transform-react-jsx -D
or
npm install babel-plugin-macros @emotion/babel-plugin-jsx-pragmatic @babel/plugin-transform-react-jsx -D
3) To the vite config.js file add the following,
// vite config.js
plugins: [
react({
babel: {
plugins: [
'babel-plugin-macros',
[
'@emotion/babel-plugin-jsx-pragmatic',
{
export: 'jsx',
import: '__cssprop',
module: '@emotion/react',
},
],
[
'@babel/plugin-transform-react-jsx',
{ pragma: '__cssprop' },
'twin.macro',
],
],
},
}),
],
4) And since we are using Typescript, we install a package to handle types in React.yarn add @types/react -D
or npm install @types/react -D
Also, create a file types/twin.d.ts in the root directory and add the following code :
import 'twin.macro'
import { css as cssImport } from '@emotion/react'
import styledImport from '@emotion/styled'
import { CSSInterpolation } from '@emotion/serialize'
declare module 'twin.macro' {
// The styled and css imports
const styled: typeof styledImport
const css: typeof cssImport
}
declare module 'react' {
// The tw and css prop
interface DOMAttributes<T> {
tw?: string
css?: CSSInterpolation
}
}
Using the TailwindCSS theme in MUI Theme
Now to extend the TailwindCSS theme to the MUI theme configuration using Twin macro, we import the tw and tailwindTheme modules from Twin Macro.
In the MUI theme.tsx file we use the tailwind theme(primary and secondary colors)and utility styling
/// theme.tsx
import { createTheme } from "@mui/material/styles";
import tw, { theme as tailwindTheme } from "twin.macro";
const theme = createTheme({
palette: {
primary: {
main: tailwindTheme`colors.primary`,
},
secondary: {
main: tailwindTheme`colors.secondary`,
},
},
components: {
MuiButton: {
styleOverrides: {
containedPrimary: {
...tw`bg-primary text-lg font-bold`,
color: tailwindTheme`colors.black`,
},
outlinedSecondary: {
backgroundColor: tailwindTheme`colors.secondary`,
color: tailwindTheme`colors.white`,
},
sizeLarge: {
height: "3.5rem",
...tw`px-8 text-base`,
},
},
},
},
});
export default theme;
Result:
With that, the MUI theme is in sync with the tailwind styling theme. You can go ahead to add more theme to your TailwindCSS and use it in your MUI Theme. Twin macro can also be used for direct styling on HTML elements too.
This starter pack can be found here