a11y-fixes
Resolve axe-core accessibility violations reported by Vitest (test/a11y.ts), Playwright (.playwright/a11y.ts), or the code-audit-frontend agent's a11y bucket.…
Patterns and conventions for all Tailwind styling. Use this skill whenever writing Tailwind class names, combining conditional classes, building component variants, or choosing between twJoin and twMerge. Also trigger when the user asks about custom values, defining @theme
$ npx -y skills add gaia-react/gaia --skill tailwind --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/tailwindContext preview
The summary Claude sees to decide when to auto-load this skill.
Patterns and conventions for all Tailwind styling. Use this skill whenever writing Tailwind class names, combining conditional classes, building component variants, or choosing between twJoin and twMerge. Also trigger when the user asks about custom values, defining @theme
name: tailwind description: Patterns and conventions for all Tailwind styling. Use this skill whenever writing Tailwind class names, combining conditional classes, building component variants, or choosing between twJoin and twMerge. 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. model: haiku
Always use Tailwind units first. For custom values, always use `rem`, never `px`.
// BAD - tailwind units available but custom rem used return <div className="p-[1.0625rem]" />; // GOOD - uses tailwind units return <div className="p-4.25" />;
Use tailwind-merge to concatenate class names in React components instead of template literals or array joins.
import {twMerge, twJoin} from 'tailwind-merge';
// BAD, template literals with potential conflicts
return <span className={`bg-gray-500 ${isBlue ? 'bg-blue-500' : ''}`} />;
// GOOD - twJoin for conditional classes, but no override needed
return <span className={twJoin('bg-gray-800', isBlue && 'text-blue-500')} />;
// GOOD, twMerge for override, twJoin for conditional classes
return <span className={twMerge('text-white', isBlue && 'text-blue-500')} />;The key distinction: use `twMerge` when a component accepts a `className` prop that should be able to override defaults, `twJoin` would leave both conflicting classes on the element, but `twMerge` resolves the conflict:
// twMerge enables callers to override component defaults
function Button({className}: {className?: string}) {
return (
<button
className={twMerge('bg-blue-500 px-4 py-2 text-white', className)}
/>
);
}
// bg-red-500 wins, twMerge removes the conflicting bg-blue-500
<Button className="bg-red-500" />;Pass falsy values directly to `twJoin` / `twMerge`, they're skipped.
// correct
twJoin('base', isActive && 'bg-blue-500', error && 'border-red-500');
// ternaries that produce two positive values are fine
twJoin('base', condition ? 'a' : 'b');Don't wrap class lists in template literals to concatenate, pass each class as a separate argument. Template literals inside `twJoin` / `twMerge` are acceptable **only** when interpolating a pre-built string from a lookup table (e.g., `ICON_POSITION[iconPosition]` from a `Record<string, string>`).
Extract multi-class variant strings into `Record` constants at the top of the file, then reference them positionally, not via interpolation.
const VARIANTS: Record<Variant, string> = {
primary: 'border border-blue-400 bg-blue-500 text-white ...',
secondary: '...',
};
// usage
twJoin('rounded-sm px-3 py-2', VARIANTS[variant]);When Tailwind's built-in scale doesn't have an exact value, use an arbitrary value with `rem`, never `px`:
// BAD, px unit <p className="text-[9px]" /> // GOOD, rem unit <p className="text-[0.5625rem]" />
Use arbitrary values sparingly. If the same custom value appears more than once, add it to the tailwind.css `@theme` instead.
When adding `@theme` tokens to `app/styles/tailwind.css`, name them by **role**, not by the utility they'll 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 stutter or nonsense, rename.
/* BAD, produces bg-bg, text-bg, border-bg-tint, text-text-muted */ --color-bg: #141413; --color-bg-tint: #181c1e; --color-text: #e0e0e0; --color-text-muted: #999; /* GOOD, produces bg-canvas, bg-surface, text-ink, text-muted */ --color-canvas: #141413; --color-surface: #181c1e; --color-ink: #e0e0e0; --color-muted: #999;
Role vocabulary that survives the lint check: `canvas`, `surface`, `surface-raised`, `ink`, `muted`, `subtle`, `primary`, `brand-*`, `success`, `warning`, `danger`, palette-style names like `claude-500`. Avoid token names starting with `bg-`, `text-`, `border-`, `ring-`, `fill-`, `stroke-`, `from-`, `to-`, `outline-`, `shadow-`.
For paired light/dark colors, prefer defining an `@utility` (like the existing `bg-body`, `text-body`) over a single `@theme` token, `@utility` binds two palette values together; a `@theme` token exposes one hex on every utility prefix.
Claude is raw power. GAIA is order and focus. The foundation that keeps Claude-shipped code production-grade as your team scales. The React frontend is handled. You build the rest of your app on top. Every convention enforced in code.
Repo: gaia-react/gaia
Resolve axe-core accessibility violations reported by Vitest (test/a11y.ts), Playwright (.playwright/a11y.ts), or the code-audit-frontend agent's a11y bucket.…
Resolve specific ESLint errors and warnings that appear in this project. Use when fixing lint failures, ESLint reported issues, or autofix conflicts (e.g.…
File a new tech-debt GitHub issue for an out-of-scope code-review finding, building the dedup key, checking for an existing open or declined-closed match, and…
Generate a comprehensive GAIA session handoff document, accomplishments, decisions, current state, open questions, so context can be cleared or compacted…
Restore context from the most recent GAIA session handoff and suggest the next action. Trigger on `/gaia-pickup` or natural-language asks like "pick up where…
Diagnose React render performance by driving a micro-interaction, capturing real renders, and surfacing memo-defeating reference instability with a recommended…