Skip to content
Security
Skill

/tailwind-4

Tailwind CSS 4 patterns and best practices. Trigger: When styling with Tailwind (className, variants, cn()), especially when dynamic styling or CSS variables are involved (no var() in className).

From plugin
prowler
15k39 skills1 MCP

Claude Code

$ npx -y skills add prowler-cloud/prowler --skill tailwind-4 --agent claude-code

SKILL.md

tailwind-4.SKILL.md
name: tailwind-4
description: >
  Tailwind CSS 4 patterns and best practices.
  Trigger: When styling with Tailwind (className, variants, cn()), especially when dynamic styling or CSS variables are involved (no var() in className).
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "1.1"
  scope: [root, ui]
  auto_invoke: "Working with Tailwind classes"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

Tailwind 4 Setup (CSS-first, no tailwind.config)

  • Config lives in CSS: `ui/styles/globals.css` starts with `@import "tailwindcss";` plus `@plugin`, `@source`, `@custom-variant`, `@theme`, `@utility`.
  • PostCSS plugin is `@tailwindcss/postcss` (`ui/postcss.config.js`). There is no `tailwind.config.*`; do not create one.
  • Design tokens are declared in `@theme` (`--color-bg-neutral-primary: ...`) and become utilities (`bg-bg-neutral-primary`, `text-text-neutral-secondary`, `border-border-neutral-secondary`).
  • Dark mode is class-based: `@custom-variant dark (&:where(.dark, .dark *));` (toggled by `next-themes`).
  • New utilities use `@utility name { ... }`, not `@layer utilities` + `@apply` hacks.

**Prowler UI:** use the semantic token utilities above. Raw palette classes (`bg-slate-800`, `bg-blue-500`) appear below only as generic Tailwind examples; in `ui/` they are not allowed (see `prowler-ui` Design System Discipline).

Styling Decision Tree

Tailwind class exists?  → className="..."
Dynamic value?          → style={{ width: `${x}%` }}
Conditional styles?     → cn("base", condition && "variant")
Static only?            → className="..." (no cn() needed)
Library can't use class?→ style prop with var() constants

Critical Rules

Never Use var() in className

// ❌ NEVER: var() in className
<div className="bg-[var(--color-primary)]" />
<div className="text-[var(--text-color)]" />

// ✅ ALWAYS: Use theme token utilities
<div className="bg-button-primary" />
<div className="text-text-neutral-secondary" />

Tailwind 4 also accepts the `bg-(--token)` shorthand for CSS variables; it is still an escape hatch. If a token is used repeatedly, it belongs in `@theme`.

Never Use Hex Colors

// ❌ NEVER: Hex colors in className
<p className="text-[#ffffff]" />
<div className="bg-[#1e293b]" />

// ✅ ALWAYS: Use theme color utilities
<p className="text-text-neutral-primary" />
<div className="bg-bg-neutral-secondary" />

The cn() Utility

Already defined in `ui/lib/utils.ts` (built on `extendTailwindMerge` so custom token classes merge correctly); import it with `import { cn } from "@/lib/utils";`. Never redefine it. Simplified shape:

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

When to Use cn()

// ✅ Conditional classes
<div className={cn("base-class", isActive && "active-class")} />

// ✅ Merging with potential conflicts
<button className={cn("px-4 py-2", className)} />  // className might override

// ✅ Multiple conditions
<div className={cn(
  "rounded-lg border",
  variant === "primary" && "bg-blue-500 text-white",
  variant === "secondary" && "bg-gray-200 text-gray-800",
  disabled && "opacity-50 cursor-not-allowed"
)} />

When NOT to Use cn()

// ❌ Static classes - unnecessary wrapper
<div className={cn("flex items-center gap-2")} />

// ✅ Just use className directly
<div className="flex items-center gap-2" />

Style Constants for Charts/Libraries

When libraries don't accept className (like Recharts):

// ✅ Constants with var() - ONLY for library props
// Prefer existing shared maps first, e.g. SEVERITY_COLORS in ui/types/severities.ts
const CHART_COLORS = {
  emptyState: "var(--border-neutral-tertiary)",
  critical: "var(--color-bg-data-critical)",
};

// Usage with Recharts (can't use className)
<Cell fill={CHART_COLORS.critical} />
<CartesianGrid stroke={CHART_COLORS.emptyState} />

Dynamic Values

// ✅ style prop for truly dynamic values
<div style={{ width: `${percentage}%` }} />
<div style={{ opacity: isVisible ? 1 : 0 }} />

// ✅ CSS custom properties for theming
<div style={{ "--progress": `${value}%` } as React.CSSProperties} />

Common Patterns

Flexbox

<div className="flex items-center justify-between gap-4" />
<div className="flex flex-col gap-2" />
<div className="inline-flex items-center" />

Grid

<div className="grid grid-cols-3 gap-4" />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6" />

Spacing

// Padding
<div className="p-4" />           // All sides
<div className="px-4 py-2" />     // Horizontal, vertical
<div className="pt-4 pb-2" />     // Top, bottom

// Margin
<div className="m-4" />
<div className="mx-auto" />       // Center horizontally
<div className="mt-8 mb-4" />

Typography

<h1 className="text-2xl font-bold text-white" />
<p className="text-sm text-slate-400" />
<span className="text-xs font-medium uppercase tracking-wide" />

Borders & Shadows

<div className="rounded-lg border border-slate-700" />
<div className="rounded-full shadow-lg" />
<div className="ring-2 ring-blue-500 ring-offset-2" />

States

<button className="hover:bg-blue-600 focus:ring-2 active:scale-95" />
<input className="focus:border-blue-500 focus:outline-none" />
<div className="group-hover:opacity-100" />

Responsive

<div className="w-full md:w-1/2 lg:w-1/3" />
<div className="hidden md:block" />
<div className="text-sm md:text-base lg:text-lg" />

Dark Mode

<div className="bg-white dark:bg-slate-900" />
<p className="text-gray-900 dark:text-white" />

Arbitrary Values (Escape Hatch)

// ✅ OK for one-off values not in design syst
Read more
@prowler-cloud
Ships withprowler

Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.

15k39 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
15.2k
Star history of prowler-cloud/prowler on GitHub, a chart by star-history.com

Other skills on prowler.

ai-sdk-5

ai-sdk-5

Vercel AI SDK patterns for the installed major (ui/package.json: `ai` 6.x, `@ai-sdk/react` 3.x). The skill name is historical;…

django-drf

django-drf

Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…

gh-aw

gh-aw

Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…

jsonapi

jsonapi

Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw10d23k
@nvidia@nvidiaInstall Skill

Questions about tailwind-4.

Which coding agents can use tailwind-4?
tailwind-4 installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.