Skip to content

[docs] Add Tailwind CSS v4 integration guide #45906

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc as a whole is very outdated and needs some serious reworking, possibly to split it up into multiple docs. As a start, what do you think about moving the Tailwind v3 info into the new v4 doc and making that the single source of truth for all Tailwind integrations? (That could also be a separate PR so we don't block this one.)

Copy link
Member Author

@siriwatknp siriwatknp Apr 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could also be a separate PR so we don't block this one.

Totally agree, that's what I think.

However, I lean toward splitting v4 from v3 because the setup is quite different.
Also, I want to leave v3 integration as a separate page because the integration is such painful (we can't do anything about it because of the technical limitation), so in v3 page there should be an info to recommend Tailwind CSS v4 instead.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ There are examples for the following styling solutions:
- [Styled Components](#styled-components)
- [CSS Modules](#css-modules)
- [Emotion](#emotion)
- [Tailwind CSS](#tailwind-css)
- [Tailwind CSS v3](#tailwind-css-v3)
- [~~JSS~~ TSS](#jss-tss)

## Plain CSS
Expand Down Expand Up @@ -573,11 +573,15 @@ It works exactly like styled components. You can [use the same guide](/material-

It works exactly like styled components. You can [use the same guide](/material-ui/integrations/interoperability/#styled-components).

## Tailwind CSS
## Tailwind CSS v3

![stars](https://img.shields.io/github/stars/tailwindlabs/tailwindcss.svg?style=social&label=Star)
![npm](https://img.shields.io/npm/dm/tailwindcss)

:::info
For Tailwind CSS v4, please refer to the [v4 integration guide](/material-ui/integrations/tailwindcss/tailwindcss-v4/).
:::

### Setup

<!-- #repo-reference -->
Expand Down
34 changes: 34 additions & 0 deletions docs/data/material/integrations/tailwindcss/TextFieldTailwind.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from 'react';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Input from '@mui/material/Input';
import FormHelperText from '@mui/material/FormHelperText';

export default function TextFieldTailwind() {
return (
<FormControl>
<InputLabel
shrink
htmlFor="component-outlined"
className="relative top-0 left-0 transform-none text-sm font-medium text-neutral-800 dark:text-neutral-200 pointer-events-auto mb-0.5"
>
Name
</InputLabel>
<Input
id="component-outlined"
placeholder="Type your name"
slotProps={{
root: {
className:
'mt-0 -ml-0.5 px-2 h-10 border-1 border-neutral-300 dark:border-neutral-700 rounded-md has-[input:focus-visible]:outline-2 has-[input:focus-visible]:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm before:hidden after:hidden',
},
input: {
className:
'placeholder:opacity-100 placeholder:text-neutral-400 dark:placeholder:text-neutral-500',
},
}}
/>
<FormHelperText className="ml-0">Some important helper text</FormHelperText>
</FormControl>
);
}
34 changes: 34 additions & 0 deletions docs/data/material/integrations/tailwindcss/TextFieldTailwind.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from 'react';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Input from '@mui/material/Input';
import FormHelperText from '@mui/material/FormHelperText';

export default function TextFieldTailwind() {
return (
<FormControl>
<InputLabel
shrink
htmlFor="component-outlined"
className="relative top-0 left-0 transform-none text-sm font-medium text-neutral-800 dark:text-neutral-200 pointer-events-auto mb-0.5"
>
Name
</InputLabel>
<Input
id="component-outlined"
placeholder="Type your name"
slotProps={{
root: {
className:
'mt-0 -ml-0.5 px-2 h-10 border-1 border-neutral-300 dark:border-neutral-700 rounded-md has-[input:focus-visible]:outline-2 has-[input:focus-visible]:outline-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm before:hidden after:hidden',
},
input: {
className:
'placeholder:opacity-100 placeholder:text-neutral-400 dark:placeholder:text-neutral-500',
},
}}
/>
<FormHelperText className="ml-0">Some important helper text</FormHelperText>
</FormControl>
);
}
133 changes: 133 additions & 0 deletions docs/data/material/integrations/tailwindcss/tailwindcss-v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Tailwind CSS v4 integration

<p class="description">Learn how to use Material UI with Tailwind CSS v4.</p>

## Overview

There are two steps to integrate Tailwind CSS v4 with Material UI:

1. Configure the styles to generate with the `@layer` directive.
2. Set up the layer order so that `mui` comes before the `utilities` layer, allowing Tailwind CSS classes to override Material UI styles.

The instructions below detail how to achieve this using common React frameworks.

### Next.js App Router

To integrate Tailwind CSS v4 with Material UI in a Next.js App Router project, start by configuring Material UI with Next.js in the [App Router integration guide](/material-ui/integrations/nextjs/#app-router).
Then follow these steps:

1. Enable the [CSS layer feature](/material-ui/integrations/nextjs/#using-other-styling-solutions) in the root layout:

```tsx title="src/app/layout.tsx"
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';

export default function RootLayout() {
return (
<html lang="en" suppressHydrationWarning>
<body>
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
{/* Your app */}
</AppRouterCacheProvider>
</body>
</html>
);
}
```

2. Configure the layer order in the Tailwind CSS file:

```css title="src/app/globals.css"
@layer theme, base, mui, components, utilities;
@import 'tailwindcss';
```

### Next.js Pages Router
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't make this work, I tried to follow the steps from the Next.js guide and this one, but Tailwind classes were not overriding the MUI styles. It would be great if we can have an example to link (together with the guides), as combining the two guides it's kind of hard to follow.

Also, I've created #45922 with bunch of issues I found on the Next.js guide.

Copy link
Member Author

@siriwatknp siriwatknp Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is expected because we haven't release #45596.

Updated the PR description to make it clear what build to use.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok, I will update my testing app to use the build from that PR.


To integrate Tailwind CSS v4 with Material UI in a Next.js Pages Router project, start by configuring Material UI with Next.js in the [Pages Router integration guide](/material-ui/integrations/nextjs/#pages-router).
Then follow these steps:

1. Enable the [CSS layer feature](/material-ui/integrations/nextjs/#configuration-2) in a custom `_document`:

```tsx title="pages/_document.tsx"
import {
createCache,
documentGetInitialProps,
} from '@mui/material-nextjs/v15-pagesRouter';

// ...

MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const finalProps = await documentGetInitialProps(ctx, {
emotionCache: createCache({ enableCssLayer: true }),
});
return finalProps;
};
```

2. Configure the layer order with the `GlobalStyles` component—it must be the first child of the `AppCacheProvider`:

```tsx title="pages/_app.tsx"
import { AppCacheProvider } from '@mui/material-nextjs/v15-pagesRouter';
import GlobalStyles from '@mui/material/GlobalStyles';

export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
return (
<AppCacheProvider {...props}>
<GlobalStyles styles="@layer theme, base, mui, components, utilities;" />
{/* Your app */}
</AppCacheProvider>
);
}
```

### Vite.js or any other SPA

To integrate Tailwind CSS v4 with Material UI in a Vite-based app, make the following changes in `src/main.tsx`:

1. Pass the `enableCssLayer` prop to the `StyledEngineProvider` component.
2. Configure the layer order with the `GlobalStyles` component.

```tsx title="main.tsx"
import { StyledEngineProvider } from '@mui/material/styles';
import GlobalStyles from '@mui/material/GlobalStyles';

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<StyledEngineProvider enableCssLayer>
<GlobalStyles styles="@layer theme, base, mui, components, utilities;" />
{/* Your app */}
</StyledEngineProvider>
</React.StrictMode>,
);
```

## Tailwind CSS IntelliSense for VS Code

The official [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension requires extra configuration to work properly when customizing the interior slots of Material UI components.
After installing the extension, add the following line to your [VS Code `settings.json`](https://code.visualstudio.com/docs/editor/settings#_settings-json-file) file:

```json
{
// ...config
"tailwindCSS.experimental.classRegex": [["className\\s*:\\s*['\"]([^'\"]*)['\"]"]]
}
```

Now you should see the autocomplete and syntax highlighting features when using the `slotProps` prop, as shown in the screenshot below:

![A preview of Tailwind CSS Intellisense](/static/material-ui/tailwind-intellisense.jpg)

## Usage

- Use the `className` prop to apply Tailwind CSS classes to the root element of the component.
- Use `slotProps.{slotName}.className` to apply Tailwind CSS classes to a component's [interior slots](/material-ui/customization/overriding-component-structure/#interior-slots).

{{"demo": "TextFieldTailwind.js"}}

## Troubleshooting

If the Tailwind CSS classes are not overriding Material UI components, make sure that:

- You are using Tailwind CSS >= v4.
- You have configured the layer order correctly by checking the [DevTools styles tab](https://developer.chrome.com/docs/devtools/css/reference#cascade-layers). The `mui` layer should come before the `utilities` layer.
5 changes: 5 additions & 0 deletions docs/data/material/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ const pages: MuiPage[] = [
pathname: '/material-ui/integrations',
title: 'Integrations',
children: [
{
pathname: '/material-ui/integrations/tailwindcss/tailwindcss-v4',
title: 'Tailwind CSS v4 integration',
newFeature: true,
},
{
pathname: '/material-ui/integrations/nextjs',
title: 'Next.js integration',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
import * as pageProps from 'docs/data/material/integrations/tailwindcss/tailwindcss-v4.md?muiMarkdown';

export default function Page() {
return <MarkdownDocs {...pageProps} />;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/translations/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"/material-ui/guides/composition": "Composition",
"/material-ui/guides/content-security-policy": "Content Security Policy",
"/material-ui/integrations": "Integrations",
"/material-ui/integrations/tailwindcss/tailwindcss-v4": "Tailwind CSS v4 integration",
"/material-ui/integrations/nextjs": "Next.js integration",
"/material-ui/integrations/routing": "Routing libraries",
"/material-ui/integrations/styled-components": "Usage with styled-components",
Expand Down
3 changes: 3 additions & 0 deletions packages/api-docs-builder/utils/replaceUrl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ describe('replaceUrl', () => {
expect(replaceUrl(`/guides/minimizing-bundle-size/`, '/material-ui/react-buttons')).to.equal(
`/material-ui/guides/minimizing-bundle-size/`,
);
expect(replaceUrl(`/integrations/tailwindcss/`, '/material-ui')).to.equal(
`/material-ui/integrations/tailwindcss/`,
);
expect(
replaceUrl(`/components/data-grid/getting-started/#main-content`, '/x/react-data-grid'),
).to.equal(`/x/react-data-grid/getting-started/#main-content`);
Expand Down
2 changes: 1 addition & 1 deletion packages/api-docs-builder/utils/replaceUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const replaceMaterialLinks = (url: string) => {
return url;
}
return url.replace(
/(guides|customization|getting-started|discover-more|experimental-api|migration)/,
/(guides|customization|getting-started|discover-more|experimental-api|migration|integrations)/,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this change to fix the wrong generated url of the deploy preview

image

In the image above, the material should be material-ui.

'material-ui/$1',
);
};
Expand Down
Loading