skills/stack/tailwind-design-system/SKILL.md
# Tailwind Design System Patterns for building consistent, maintainable UIs with Tailwind CSS. Use design tokens, component variants, and the `cn()` utility to keep styling predictable and composable. --- ## The cn() Utility Use `cn()` (powered by `clsx` + `tailwind-merge`) for all conditional and merged class names. Never do string concatenation for Tailwind classes. ```tsx import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs
npx skillsauth add 33prime/rtg-forge skills/stack/tailwind-design-systemInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Patterns for building consistent, maintainable UIs with Tailwind CSS. Use design tokens, component variants, and the cn() utility to keep styling predictable and composable.
Use cn() (powered by clsx + tailwind-merge) for all conditional and merged class names. Never do string concatenation for Tailwind classes.
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
clsx handles conditional classes: clsx("base", isActive && "bg-blue-500")tailwind-merge resolves conflicts: twMerge("px-4 px-6") becomes "px-6"Use class-variance-authority (cva) for components with multiple variants:
import { cva, type VariantProps } from "class-variance-authority";
const buttonVariants = cva(
// Base classes applied to ALL variants
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
sm: "h-8 px-3 text-xs",
md: "h-10 px-4 py-2",
lg: "h-12 px-8 text-base",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
},
);
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
function Button({ className, variant, size, ...props }: ButtonProps) {
return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;
}
cva()variantsdefaultVariantsclassName prop and merge with cn() for overridesUse Tailwind's spacing/color/typography scale consistently. Never use arbitrary values when a scale value exists.
Use: p-1 p-2 p-3 p-4 p-6 p-8 p-12 p-16
Avoid: p-[7px] p-[13px] p-[22px]
Stick to the Tailwind spacing scale (multiples of 4px by default). Use arbitrary values only when matching exact design specs from Figma.
Define semantic colors in tailwind.config.ts:
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
},
},
},
};
Then reference semantic tokens in components:
// YES — semantic tokens
<div className="bg-background text-foreground border-border" />
// NO — hardcoded colors
<div className="bg-white text-gray-900 border-gray-200" />
Use Tailwind's mobile-first responsive prefixes. Design for mobile, then add breakpoints.
// Mobile-first: stack on mobile, grid on larger screens
<div className="flex flex-col gap-4 sm:grid sm:grid-cols-2 lg:grid-cols-3">
{items.map((item) => (
<Card key={item.id} />
))}
</div>
| Prefix | Min Width | Use For |
|---|---|---|
| (none) | 0px | Mobile base |
| sm: | 640px | Large phones, small tablets |
| md: | 768px | Tablets |
| lg: | 1024px | Small laptops |
| xl: | 1280px | Desktops |
| 2xl: | 1536px | Large desktops |
sm: and up for progressive enhancementImplement dark mode using CSS variables and Tailwind's dark: prefix.
/* globals.css */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
}
}
// Components automatically adapt via CSS variables
<div className="bg-background text-foreground">
Adapts to light/dark automatically
</div>
// For cases where you need explicit dark overrides:
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
Explicit dark mode override
</div>
dark: only when CSS variables are insufficient<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
{/* Content constrained to max width with responsive padding */}
</div>
<div className="flex flex-col gap-4">
<Component />
<Component />
</div>
<div className="flex flex-wrap gap-2">
<Tag />
<Tag />
<Tag />
</div>
<div className="flex flex-col md:flex-row gap-6">
<aside className="w-full md:w-64 shrink-0">Sidebar</aside>
<main className="flex-1 min-w-0">Content</main>
</div>
// BAD: Inline styles mixed with Tailwind
<div className="flex gap-4" style={{ padding: "20px", backgroundColor: "#f0f0f0" }}>
// BAD: String concatenation for classes
<div className={"px-4 " + (isActive ? "bg-blue-500" : "bg-gray-500")}>
// BAD: Arbitrary values when scale values exist
<div className="p-[16px] m-[24px] text-[14px]">
// Should be: p-4 m-6 text-sm
// BAD: Not using cn() for conditional classes
<div className={`px-4 ${isActive ? "bg-blue-500" : ""} ${isLarge ? "text-lg" : ""}`}>
// Should be: cn("px-4", isActive && "bg-blue-500", isLarge && "text-lg")
development
# Parallel Execution > This skill is under development. Workflow patterns for running independent tasks in parallel to improve performance and throughput. ## Topics to Cover - Identifying independent tasks suitable for parallel execution - `asyncio.gather()` with `return_exceptions=True` - `asyncio.TaskGroup` for structured concurrency (Python 3.11+) - Semaphores for bounded concurrency - `Promise.all()` and `Promise.allSettled()` in TypeScript - Handling partial failures (some tasks succeed
development
# Module Extraction > This skill is under development. Workflow for identifying and extracting reusable modules from existing codebases. Extract when a pattern is used in 3+ places and has stabilized. ## Topics to Cover - Identifying extraction candidates (rule of three) - Defining module boundaries and public interface - Dependency analysis: what does the module need? - Interface design: protocols, abstract base classes - Step-by-step extraction process - Testing strategy: tests before, dur
development
# Forge Orchestrate — Intelligent Build Orchestration You are a build planner, not a build executor. Your job is to look at a project, figure out what's left to build, decompose the work into parallel streams, assign the right intelligence level to each stream, estimate cost, and hand the user a set of terminal commands they can run. You plan. They execute. --- ## Stream Decomposition The unit of parallelism is a **stream** — a self-contained bundle of tasks that one Claude session handles e
development
# Code Review > This skill is under development. Workflow for conducting effective code reviews that catch real issues and improve code quality. ## Topics to Cover - Review priorities: correctness > design > performance > style - What to check in every review (checklist) - How to give constructive feedback - Automated checks that should run before human review - Review scope: how big is too big? - Patterns for reviewing database migrations - Patterns for reviewing API changes - When to reque