Skip to content
Development
Skill

/tailwind

Applies GAIA's patterns and conventions for all Tailwind styling. Use this skill whenever writing Tailwind class names, combining classes with `cn`, writing conditional classes, or building component variants. Also trigger when the user asks about custom values, defining @theme

From plugin
gaia
2619 skills18 agents12 commands

Claude Code

$ npx -y skills add gaia-harness/gaia --skill tailwind --agent claude-code

SKILL.md

tailwind.SKILL.md
name: tailwind
description: Applies GAIA's patterns and conventions for all Tailwind styling. Use this skill whenever writing Tailwind class names, combining classes with `cn`, writing conditional classes, or building component variants. Also trigger when the user asks about custom values, defining @theme tokens or CSS variables, naming color/spacing tokens, rem vs px, responsive breakpoints, or avoiding template literal class strings.

Tailwind

Contents: Colors; cn; Conditional classes; Variants with cva; Custom Values; When to create a role token.

Colors

Every color is a theme role token (`bg-background`, `text-foreground`, `text-muted-foreground`, `bg-primary`, `text-primary-foreground`, `border-input`, `text-destructive`), never a raw palette class or an arbitrary color. The contract and where the token list lives: `apps/web/.claude/rules/tailwind.md`. The light and dark values live in the token, so write one utility, not a `dark:` pair.

// BAD, raw palette classes and a dark: pair
return <p className="bg-white text-gray-900 dark:bg-gray-900 dark:text-white" />;

// GOOD, role tokens carry both themes
return <p className="bg-background text-foreground" />;

cn

`cn` is the only class utility. Use it to combine class names in React components instead of template literals or array joins.

import {cn} from 'cn';

`cn` joins its arguments and merges conflicting utilities, so a component default can be overridden by a caller. Put the caller's `className` last: the later class wins on conflict.

import {cn} from 'cn';

// BAD, template literals with potential conflicts
return <span className={`bg-muted ${isActive ? 'bg-accent' : ''}`} />;

// GOOD, cn skips falsy values and resolves conflicts
return <span className={cn('text-foreground', isActive && 'bg-accent')} />;

// GOOD, callers can override component defaults
const Badge = ({className}: {className?: string}) => (
  <span className={cn('bg-muted px-4 py-2 text-foreground', className)} />
);

// bg-accent wins, cn removes the conflicting bg-muted
<Badge className="bg-accent" />;

Conditional classes

Write a conditional class as `cond && 'class'`, and `!cond && 'class'` when negated. Falsy values are skipped.

// correct
cn('base', isActive && 'bg-accent', !isDisabled && 'hover:bg-muted');

// a ternary with two class values is fine for either/or
cn('base', condition ? 'text-foreground' : 'text-muted-foreground');

Lint rejects object conditionals and ternaries with an empty branch passed to `cn` (`cn-conditional/cn-conditional` from `@gaia-harness/lint`), in components, tests, and stories alike.

Variants with cva

A component has variants when a prop's value selects a class string. Declare them with `cva` from `class-variance-authority` at the top of the file, then pass the result through `cn` with the caller's `className` last. Never write an object or `Record` whose values are Tailwind class strings keyed by a prop, and never index one into `cn`.

import {cva} from 'class-variance-authority';
import {cn} from 'cn';

const statusVariants = cva('rounded-md px-2 py-1 text-sm', {
  defaultVariants: {tone: 'neutral'},
  variants: {
    tone: {
      danger: 'bg-destructive text-primary-foreground',
      neutral: 'bg-muted text-muted-foreground',
    },
  },
});

type StatusProps = {
  className?: string;
  tone?: 'danger' | 'neutral';
};

const Status = ({className, tone}: StatusProps) => (
  <span className={cn(statusVariants({tone}), className)} />
);

Boolean variants key on `true` and `false`. For the variant prop's type, `VariantProps<typeof statusVariants>` keeps it in sync with the cva call. Vendored `components/ui/*.tsx` files already use cva this way; they are not a style reference for GAIA's own components (`apps/web/.claude/rules/shadcn-ui.md`).

Custom Values

Prefer Tailwind's scale (`p-4.25`, `min-w-9`, `text-xs`) and existing tokens. An arbitrary value is allowed only where neither fits (`bg-size-[200%_100%]`, `grid-cols-[auto_1fr]`); add a token to `app/styles/tailwind.css` `@theme` when the same custom value appears more than once. Lint enforces the edges: `better-tailwindcss/enforce-canonical-classes` rewrites an arbitrary value that has a scale equivalent (`w-[16px]` to `w-4`), and an arbitrary color is an error (colors are role tokens, see above). Write `rem`, not `px`.

// BAD, arbitrary value where a scale step fits
<p className="mt-[1rem]" />

// GOOD, scale value
<p className="mt-4" />

// GOOD, no scale step or token expresses this
<div className="grid grid-cols-[auto_1fr]" />

When to create a role token

1. **Use an existing token first.** Search the `:root` and `.dark` blocks in `app/styles/theme.css`. Most needs are covered (`muted`, `accent`, `destructive`, `border`, `input`, `ring`). 2. **A token equal to an existing value needs no approval.** Adding a role token whose value equals an existing token, or a value the code already repeats in more than one place, just names a role that already exists. Add it to both blocks of `theme.css` and map it in the `@theme inline` block of `tailwind.css`. 3. **A new color value asks first.** Introducing a value the theme does not already contain is a design decision: ask the adopter, and while `wiki/concepts/Design System.md` has `established: false`, follow `apps/web/.claude/rules/design-baseline.md`. 4. **Never a raw class for a one-off.** If a color has no token, it needs one (rules 2 or 3), not a raw palette class or an arbitrary color at the call site.

Naming a token

Name tokens by **role**, not by the utility they will be used with. The CSS variable suffix becomes the suffix on every generated utility (`bg-`, `text-`, `border-`, `ring-`, `fill-`, `stroke-`, `from-`, `to-`, etc.), so a token containing a utility prefix produces stuttering class names.

**Lint check before naming:** mentally expand `bg-{name}`, `text-{name}`, `border-{name}`. If any reads as a s

Read more
@gaia-react
Ships withgaia

Claude is raw power. GAIA is order and focus. A serious harness for Claude Code. It keeps Claude-shipped code production-grade as your team scales. The React frontend is handled. You build the rest of your app on top.

2619 skills18 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
26
Star history of gaia-react/gaia on GitHub, a chart by star-history.com

Other skills on gaia.

file-tech-debt

file-tech-debt

Files a new tech-debt GitHub issue for an out-of-scope code-review finding. Builds the dedup key, skips an open or…

@gaia-react@gaia-reactInstall Skill
gaia-wiki

gaia-wiki

Runs GAIA wiki maintenance (sync, consolidate, lint with fixes) in one command and lands it as one commit and PR. Trigger on…

@gaia-react@gaia-reactInstall Skill
naming-conventions

naming-conventions

Applies descriptive, self-documenting naming in any language (TypeScript, bash, workflow YAML, Dockerfiles). Use this skill…

@gaia-react@gaia-reactInstall Skill
release-notes

release-notes

Maintainer-only. Rewrites a version's GAIA CHANGELOG entries as plain-language public release notes for the marketing site…

@gaia-react@gaia-reactInstall Skill
tdd

tdd

Runs test-driven development with a red-green-refactor loop, an opt-in tool for logic where test-first helps. Use when the user…

@gaia-react@gaia-reactInstall Skill
update-deps

update-deps

Remediates dependencies in place of Dependabot version and security updates. Discovers outdated packages and open security…

@gaia-react@gaia-reactInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc11d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about tailwind.

Which coding agents can use tailwind?
tailwind 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.