# How to Set Up Angular Material with Tailwind CSS in Angular 21 (Clean & Correct Way)

Angular Material and Tailwind CSS solve **different problems**:

* **Angular Material** provides:
    
    * Accessibility
        
    * Interaction behavior
        
    * Battle-tested UI components
        
* **Tailwind CSS** provides:
    
    * Rapid layout
        
    * Utility-first styling
        
    * Design consistency at scale
        

In Angular 21, combining them **incorrectly** leads to confusing Sass errors due to **Material theming API changes**.

This guide shows the **only clean, future-proof way** to integrate both — without hacks, legacy APIs, or compiler conflicts.

---

## Core Principle (Very Important)

To avoid all known issues:

> **Material → SCSS**  
> **Tailwind → CSS**  
> **Connect them ONLY via CSS variables**

No Tailwind inside SCSS.  
No Sass inside CSS.  
No legacy Material APIs.

---

## Why Most Tutorials Break on Angular 21

Starting from Angular Material v17 and fully enforced in v21:

* Legacy Material theming APIs were removed
    
* M2 theming APIs were namespaced
    
* Palette exports changed
    
* Sass import paths changed
    

### ❌ What no longer works

```scss
@import '@angular/material/theming';
mat.define-palette(...)
$blue-palette
```

### ✅ What works in Angular 21

```scss
mat.m2-define-palette(...)
mat.$m2-blue-palette
```

---

## Step 1: Install Dependencies

```bash
ng add @angular/material
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
```

Ensure you are on:

* Angular 21
    
* Angular Material 21
    
* Tailwind 3+
    

---

## Step 2: Configure `angular.json`

You must include **two style files**, in this order:

```json
"styles": [
  "src/material-theme.scss",
  "src/styles.css"
]
```

Why order matters:

* Material defines CSS variables first
    
* Tailwind consumes them later
    

---

## Step 3: Angular Material Theme (SCSS Only)

📁 `src/material-theme.scss`

This file:

* Uses **Material v21 M2 APIs**
    
* Defines palettes
    
* Exposes **CSS variables**
    
* Contains **zero Tailwind**
    

```scss
@use '@angular/material' as mat;

/* Material core */
@include mat.core();

/* M2 palettes (Angular Material v21 compatible) */
$primary-palette: mat.m2-define-palette(mat.$m2-blue-palette);
$accent-palette: mat.m2-define-palette(mat.$m2-teal-palette);
$warn-palette: mat.m2-define-palette(mat.$m2-red-palette);

/* Light theme */
$light-theme: mat.m2-define-light-theme((
  color: (
    primary: $primary-palette,
    accent: $accent-palette,
    warn: $warn-palette,
  ),
));

/* Apply Material styles */
@include mat.all-component-themes($light-theme);

/* Expose colors as CSS variables */
:root {
  --color-primary: #{mat.m2-get-color-from-palette($primary-palette)};
  --color-primary-contrast: #{mat.m2-get-color-from-palette($primary-palette, default-contrast)};

  --color-accent: #{mat.m2-get-color-from-palette($accent-palette)};
  --color-accent-contrast: #{mat.m2-get-color-from-palette($accent-palette, default-contrast)};

  --color-warn: #{mat.m2-get-color-from-palette($warn-palette)};

  /* App tokens */
  --color-background: 255 255 255;
  --color-surface: 249 250 251;
  --color-border: 229 231 235;

  --color-text-primary: 0 0 0;
  --color-text-secondary: 75 85 99;
}
```

### Why CSS Variables?

They are:

* Framework-agnostic
    
* Runtime-switchable
    
* Safe for Tailwind
    
* Safe for Material
    

---

## Step 4: Tailwind Configuration (Consumes Variables)

📁 `tailwind.config.ts`

Tailwind never defines colors directly.  
It **reads from Material tokens**.

```ts
import type { Config } from 'tailwindcss';

const config: Config = {
  content: ['./src/**/*.{html,ts}'],
  theme: {
    extend: {
      colors: {
        primary: 'rgb(var(--color-primary) / <alpha-value>)',
        primaryContrast: 'rgb(var(--color-primary-contrast) / <alpha-value>)',

        accent: 'rgb(var(--color-accent) / <alpha-value>)',
        accentContrast: 'rgb(var(--color-accent-contrast) / <alpha-value>)',

        warn: 'rgb(var(--color-warn) / <alpha-value>)',

        background: 'rgb(var(--color-background) / <alpha-value>)',
        surface: 'rgb(var(--color-surface) / <alpha-value>)',
        border: 'rgb(var(--color-border) / <alpha-value>)',

        textPrimary: 'rgb(var(--color-text-primary) / <alpha-value>)',
        textSecondary: 'rgb(var(--color-text-secondary) / <alpha-value>)',
      },
    },
  },
  plugins: [],
};

export default config;
```

This enables:

* `bg-primary`
    
* `text-accent`
    
* `border-border`
    
* Opacity utilities like `bg-primary/80`
    

---

## Step 5: Tailwind Styles (CSS Only)

📁 `src/styles.css`

This file contains:

* Tailwind directives
    
* Plain CSS
    
* **No Sass**
    

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Global styles */
html,
body {
  height: 100%;
}

body {
  margin: 0;
  background-color: rgb(var(--color-background));
  color: rgb(var(--color-text-primary));
  font-family: Roboto, "Helvetica Neue", sans-serif;
}
```

---

## Step 6: Usage Examples

### Material + Tailwind Together

```html
<button
  mat-raised-button
  color="primary"
  class="px-6 py-2 rounded-lg"
>
  Save
</button>
```

### Tailwind-Only Component (Still Material Colors)

```html
<div class="bg-surface border border-border text-textPrimary p-4 rounded-xl">
  Dashboard Card
</div>
```

Result:

* Perfect color consistency
    
* No overrides
    
* No conflicts
    

---

## Common Mistakes to Avoid

| Mistake | Why it breaks |
| --- | --- |
| Using legacy theming APIs | Removed in v21 |
| Importing Material in CSS | Sass not allowed |
| Importing Tailwind in SCSS | PostCSS conflict |
| Defining colors twice | Design drift |
| Overriding Material internals | Upgrade risk |

---

## Why This Architecture Is Enterprise-Safe

* Clear ownership of responsibilities
    
* Upgrade-safe for Angular 22+
    
* Works with SSR and hydration
    
* Easy to document and scale
    
* Ideal for internal design systems
    

This pattern is used in **large Angular codebases** for a reason.

---

## Next Enhancements You Can Add Safely

* Dark mode (via CSS variable switching)
    
* Typography token alignment
    
* Material elevation → Tailwind shadows
    
* Theme switch service
    
* Nx-based UI library extraction
    
* Storybook integration
    

---

## Final Thoughts

If you are on **Angular 21**, this is **the correct way** to combine Angular Material and Tailwind CSS.

Anything else is either:

* Legacy
    
* Fragile
    
* Or already deprecated
    

This setup will remain stable for years.

---
