angular-tailwind

Tailwind CSS 4 patterns and best practices for Angular projects. Trigger: When styling Angular templates with Tailwind utilities, dynamic class bindings, and theme variables.

When to Use

  • Build or refactor Angular templates with Tailwind utilities.
  • Define rules for conditional classes in Angular with class bindings.
  • Apply dynamic style values in Angular without falling back to inline anti-patterns.
  • Keep Tailwind usage aligned with Angular 21 conventions and Tailwind v4 setup.

Critical Rules

Use Tailwind v4 Setup Only

/* ✅ Tailwind v4 in global styles */
@use 'tailwindcss';
{
  "plugins": {
    "@tailwindcss/postcss": {}
  }
}

Do not use v3 directives like @tailwind base/components/utilities and avoid adding tailwind.config.js unless explicitly required by a specific workflow.

Angular Template Syntax Only

Use Angular bindings instead of JSX or React patterns:

<!-- ✅ static classes -->
<div class="flex items-center gap-2"></div>

<!-- ✅ conditional classes -->
<button
  class="px-4 py-2 rounded"
  [class.opacity-50]="disabled"
  [class.cursor-not-allowed]="disabled"
>
  Guardar
</button>

<!-- ✅ map-style class binding -->
<div
  [class]="{
    'rounded-lg border': true,
    'bg-blue-600 text-white': variant() === 'primary',
    'bg-slate-200 text-slate-900': variant() === 'secondary'
  }"
></div>

Avoid var() and Hex Inside Utility Class Strings

<!-- ❌ avoid arbitrary var() and hex in class -->
<div class="bg-[var(--color-primary)]"></div>
<p class="text-[#ffffff]"></p>

<!-- ✅ use semantic/design-system classes -->
<div class="bg-primary"></div>
<p class="text-white"></p>

Dynamic Values Go in Style Bindings

progress = signal(72);
isVisible = signal(true);
<!-- ✅ dynamic values in style binding -->
<div [style.width.%]="progress()"></div>
<div [style.opacity]="isVisible() ? 1 : 0"></div>

Use Signals for Style Decisions

variant = signal<'primary' | 'secondary'>('primary');
isDisabled = signal(false);
<button
  class="px-4 py-2 rounded transition"
  [class.bg-blue-600]="variant() === 'primary'"
  [class.text-white]="variant() === 'primary'"
  [class.bg-slate-200]="variant() === 'secondary'"
  [class.text-slate-900]="variant() === 'secondary'"
  [class.opacity-50]="isDisabled()"
>
  Acción
</button>

Common Angular Patterns

Layout and Spacing

<section class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
  <article class="rounded-xl border border-slate-200 p-4 shadow-sm"></article>
</section>

<div class="mx-auto w-full max-w-5xl px-4 py-8"></div>

Typography and States

<h1 class="text-2xl font-bold tracking-tight text-slate-900 md:text-3xl"></h1>
<p class="text-sm text-slate-600"></p>

<button
  class="rounded-lg bg-blue-600 px-4 py-2 text-white transition hover:bg-blue-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500"
></button>

Lists with New Control Flow

<ul class="space-y-2">
  @for (item of items(); track item.id) {
    <li class="rounded border border-slate-200 p-3">{{ item.name }}</li>
  }
</ul>

Dark Mode

<div class="bg-white text-slate-900 dark:bg-slate-900 dark:text-slate-100"></div>

Commands

pnpm add -D tailwindcss @tailwindcss/postcss postcss
pnpm build

Resources