Tailwind css
Universal AI development toolkit. 74 production-ready skills for every coding agent. Works with Claude Code, Cursor, Codex.
npx -y skills add medy-gribkov/arcana --skill tailwind-cssAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Apply Tailwind CSS v4 patterns, custom plugins, responsive design, dark mode, cn() utility, and performance optimization. Avoid common anti-patterns.
SKILL.md
13.3 KB, as published. Nobody here has run it
Tailwind CSS Skill
Core Configuration (v4)
BAD: Mixing inline styles with Tailwind
// C:\Users\Dev\components\Button.tsx
export function Button() {
return (
<button
style={{ padding: '12px 24px' }}
className="bg-blue-500"
>
Click me
</button>
);
}
GOOD: Pure Tailwind with custom design tokens
// C:\Users\Dev\components\Button.tsx
export function Button() {
return (
<button className="px-6 py-3 bg-blue-500 hover:bg-blue-600 transition-colors">
Click me
</button>
);
}
// tailwind.config.ts
import type { Config } from 'tailwindcss';
export default {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
spacing: {
'18': '4.5rem',
'88': '22rem',
},
colors: {
brand: {
50: '#f0f9ff',
500: '#3b82f6',
900: '#1e3a8a',
},
},
},
},
} satisfies Config;
cn() Utility Pattern
BAD: String concatenation without proper merging
// C:\Users\Dev\components\Card.tsx
interface CardProps {
className?: string;
variant?: 'default' | 'outlined';
}
export function Card({ className, variant = 'default' }: CardProps) {
const baseClasses = 'p-4 rounded-lg';
const variantClasses = variant === 'default'
? 'bg-white shadow'
: 'border border-gray-300';
// Problem: conflicting classes not merged properly
return <div className={`${baseClasses} ${variantClasses} ${className}`} />;
}
// Usage causes conflicts
<Card className="p-8 bg-blue-50" /> // p-8 and bg-blue-50 don't override properly
GOOD: Proper cn() with clsx and tailwind-merge
// C:\Users\Dev\lib\utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// C:\Users\Dev\components\Card.tsx
import { cn } from '@/lib/utils';
interface CardProps {
className?: string;
variant?: 'default' | 'outlined';
}
export function Card({ className, variant = 'default' }: CardProps) {
return (
<div
className={cn(
'p-4 rounded-lg',
variant === 'default' && 'bg-white shadow',
variant === 'outlined' && 'border border-gray-300',
className
)}
/>
);
}
// Usage properly overrides
<Card className="p-8 bg-blue-50" /> // p-8 and bg-blue-50 override correctly
Responsive Design Patterns
BAD: Mobile-last with max-width breakpoints
// C:\Users\Dev\components\Grid.tsx
export function Grid() {
return (
<div className="grid-cols-4 md:grid-cols-2 sm:grid-cols-1">
{/* Content */}
</div>
);
}
GOOD: Mobile-first progressive enhancement
// C:\Users\Dev\components\Grid.tsx
export function Grid() {
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{/* Content */}
</div>
);
}
// Custom breakpoint configuration
// tailwind.config.ts
export default {
theme: {
screens: {
'xs': '475px',
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
},
},
} satisfies Config;
Dark Mode Implementation
BAD: Manual dark mode with separate classes
// C:\Users\Dev\components\Panel.tsx
export function Panel({ isDark }: { isDark: boolean }) {
return (
<div className={isDark ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'}>
Content
</div>
);
}
GOOD: Class-based dark mode with system preference
// tailwind.config.ts
export default {
darkMode: 'class', // or 'media' for system preference only
// ...
} satisfies Config;
// C:\Users\Dev\components\Panel.tsx
export function Panel() {
return (
<div className="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
Content
</div>
);
}
// C:\Users\Dev\app\layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className="dark" suppressHydrationWarning>
<body>{children}</body>
</html>
);
}
Custom Plugin Development
BAD: Repetitive utility classes
// C:\Users\Dev\components\GlassCard.tsx
export function GlassCard() {
return (
<div className="backdrop-blur-md bg-white/10 border border-white/20 rounded-lg shadow-xl">
Content
</div>
);
}
// Used in 20+ places with same pattern
GOOD: Custom plugin for reusable patterns
// tailwind.config.ts
import plugin from 'tailwindcss/plugin';
export default {
plugins: [
plugin(function({ addUtilities, addComponents, theme }) {
addUtilities({
'.glass': {
'backdrop-filter': 'blur(12px)',
'background-color': 'rgba(255, 255, 255, 0.1)',
'border': '1px solid rgba(255, 255, 255, 0.2)',
},
'.glass-dark': {
'backdrop-filter': 'blur(12px)',
'background-color': 'rgba(0, 0, 0, 0.1)',
'border': '1px solid rgba(0, 0, 0, 0.2)',
},
});
addComponents({
'.btn-primary': {
padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
borderRadius: theme('borderRadius.lg'),
backgroundColor: theme('colors.blue.500'),
color: theme('colors.white'),
'&:hover': {
backgroundColor: theme('colors.blue.600'),
},
},
});
}),
],
} satisfies Config;
// C:\Users\Dev\components\GlassCard.tsx
export function GlassCard() {
return <div className="glass rounded-lg shadow-xl">Content</div>;
}
Anti-Pattern: @apply Overuse
BAD: CSS file full of @apply
/* C:\Users\Dev\styles\components.css */
.button {
@apply px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors;
}
.card {
@apply p-6 bg-white rounded-lg shadow-md dark:bg-gray-800;
}
.input {
@apply w-full px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500;
}
/* Defeats Tailwind's purpose, loses composability */
GOOD: Component abstraction with Tailwind classes
// C:\Users\Dev\components\ui\Button.tsx
import { cn } from '@/lib/utils';
import { type VariantProps, cva } from 'class-variance-authority';
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-lg font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-blue-500 text-white hover:bg-blue-600',
outline: 'border border-gray-300 bg-transparent hover:bg-gray-100',
ghost: 'hover:bg-gray-100',
},
size: {
sm: 'h-9 px-3 text-sm',
md: 'h-10 px-4',
lg: 'h-11 px-8',
},
},
defaultVariants: {
variant: 'default',
size: 'md',
},
}
);
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
export function Button({ className, variant, size, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
Animation Utilities
BAD: Custom CSS animations without tokens
/* C:\Users\Dev\styles\animations.css */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
GOOD: Tailwind animation configuration
// tailwind.config.ts
export default {
theme: {
extend: {
keyframes: {
fadeIn: {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
shimmer: {
'0%': { backgroundPosition: '-200% 0' },
'100%': { backgroundPosition: '200% 0' },
},
},
animation: {
'fade-in': 'fadeIn 0.5s ease-out',
'shimmer': 'shimmer 2s infinite linear',
},
},
},
} satisfies Config;
// C:\Users\Dev\components\Skeleton.tsx
export function Skeleton() {
return (
<div className="relative overflow-hidden rounded bg-gray-200 dark:bg-gray-800">
<div className="animate-shimmer bg-gradient-to-r from-transparent via-white/10 to-transparent" />
</div>
);
}
Performance: JIT and Content Configuration
BAD: Scanning too many files
// tailwind.config.ts
export default {
content: [
'./**/*.{js,ts,jsx,tsx}', // Scans node_modules, .git, etc.
],
} satisfies Config;
GOOD: Precise content paths with safelist
// tailwind.config.ts
export default {
content: [
'./src/app/**/*.{js,ts,jsx,tsx}',
'./src/components/**/*.{js,ts,jsx,tsx}',
'./src/lib/**/*.{js,ts,jsx,tsx}',
],
safelist: [
// Dynamic classes that might be missed
'bg-red-500',
'bg-green-500',
'bg-blue-500',
{
pattern: /bg-(red|green|blue)-(400|500|600)/,
variants: ['hover', 'dark'],
},
],
} satisfies Config;
// C:\Users\Dev\components\Alert.tsx
const colorMap = {
error: 'bg-red-500',
success: 'bg-green-500',
info: 'bg-blue-500',
} as const;
// Safelisted ensures these dynamic classes aren't purged
export function Alert({ type }: { type: keyof typeof colorMap }) {
return <div className={colorMap[type]}>Alert</div>;
}
Container Queries
BAD: Media queries for component-level responsiveness
// C:\Users\Dev\components\Card.tsx
export function Card() {
return (
<div className="p-4 md:p-6 lg:p-8">
<h2 className="text-lg md:text-xl lg:text-2xl">Title</h2>
</div>
);
}
// Breaks when card is in narrow sidebar on large screen
GOOD: Container queries for true component responsiveness
// tailwind.config.ts
export default {
plugins: [
require('@tailwindcss/container-queries'),
],
} satisfies Config;
// C:\Users\Dev\components\Card.tsx
export function Card() {
return (
<div className="@container">
<div className="p-4 @md:p-6 @lg:p-8">
<h2 className="text-lg @md:text-xl @lg:text-2xl">Title</h2>
</div>
</div>
);
}
Arbitrary Values and CSS Variables
BAD: Hardcoded magic values
// C:\Users\Dev\components\Hero.tsx
export function Hero() {
return (
<section className="h-[calc(100vh-64px)] pt-[72px]">
Content
</section>
);
}
GOOD: CSS variables with Tailwind arbitrary values
/* C:\Users\Dev\styles\globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--header-height: 64px;
--content-padding: 72px;
}
}
// C:\Users\Dev\components\Hero.tsx
export function Hero() {
return (
<section className="h-[calc(100vh-var(--header-height))] pt-[var(--content-padding)]">
Content
</section>
);
}
Form Patterns with Focus States
GOOD: Accessible form components with proper focus
// C:\Users\Dev\components\ui\Input.tsx
import { cn } from '@/lib/utils';
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: string;
}
export function Input({ className, error, ...props }: InputProps) {
return (
<div className="space-y-1">
<input
className={cn(
'w-full rounded-lg border bg-white px-3 py-2 text-sm',
'transition-colors placeholder:text-gray-400',
'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',
'disabled:cursor-not-allowed disabled:opacity-50',
'dark:bg-gray-900 dark:border-gray-700',
error && 'border-red-500 focus:ring-red-500',
className
)}
{...props}
/>
{error && <p className="text-sm text-red-500">{error}</p>}
</div>
);
}
Workflow: Apply This Skill
- Audit className usage: Search for string concatenation without cn()
- Check @apply usage: Refactor CSS files into component abstractions
- Verify content paths: Ensure tailwind.config.ts scans only source files
- Test dark mode: Verify dark: variants work across all components
- Review responsive design: Confirm mobile-first breakpoint usage
- Validate animations: Check keyframes are in config, not separate CSS
- Check dynamic classes: Add patterns to safelist if computed at runtime
- Performance check: Run
npm run buildand verify CSS bundle size
Installation Commands
# Install Tailwind CSS v4
npm install -D tailwindcss@next @tailwindcss/postcss@next
# Install utilities
npm install clsx tailwind-merge class-variance-authority
# Install official plugins
npm install -D @tailwindcss/forms @tailwindcss/typography @tailwindcss/container-queries
Common Fixes
Fix: Tailwind classes not applying
- Check content paths in tailwind.config.ts include the file
- Verify PostCSS config includes tailwindcss plugin
- Clear .next cache:
rm -rf .next - Check class isn't being overridden by CSS specificity
Fix: Dynamic classes not working
- Add pattern to safelist in tailwind.config.ts
- Use complete class strings, not template literals with partial classes
- Bad:
text-${color}-500| Good: colorMap object with full class names
Fix: Dark mode not switching
- Verify darkMode: 'class' in config
- Check html element has 'dark' class applied
- Ensure dark: variants are on affected elements