Skip to main content

Command Palette

Search for a command to run...

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

Published
4 min read
S

Technology Enthusiast and voracious reader with a demonstrated history of working in the computer software industry. Skilled in PHP, JavaScript, NodeJS, Angular, MySQL, MongoDB, Web3, Product Development, Project Management, and Teamwork.

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

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

✅ What works in Angular 21

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

Step 1: Install Dependencies

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:

"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

@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.

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

@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

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

Tailwind-Only Component (Still Material Colors)

<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

MistakeWhy it breaks
Using legacy theming APIsRemoved in v21
Importing Material in CSSSass not allowed
Importing Tailwind in SCSSPostCSS conflict
Defining colors twiceDesign drift
Overriding Material internalsUpgrade 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.


More from this blog

V

Voice of Dev

17 posts