- Introduction
- What Are Claude Code Skills?
- Anatomy of a Skill
- The Modern React + Tailwind + Framer Motion Stack
- Building the Skill: Step by Step
- Using the Skill in a Project
- Advanced Skill Features
- Testing and Iterating
- Appendix A: Claude Code Skills Research
- Appendix B: React + Tailwind + Framer Motion Research
This tutorial teaches you two things at once:
- How to create a Claude Code skill -- a reusable package of instructions that extends Claude's capabilities
- How to encode modern React + Tailwind + Framer Motion best practices into that skill so Claude generates beautiful, elegant, clean, and organized UI code every time
By the end, you'll have a working skill called beautiful-react-ui that you can invoke with /beautiful-react-ui or that Claude activates automatically when you ask it to build UI components.
- Developers using Claude Code who want consistent, high-quality React component output
- Teams wanting to encode their UI patterns into a shareable, version-controlled skill
- Anyone learning the Claude Code skills system
- Claude Code installed and working
- Basic familiarity with React, Tailwind CSS, and component-based development
Skills are folders of instructions, scripts, and resources that Claude loads when relevant to your task. Think of them as specialized knowledge modules that transform Claude from a general-purpose coding assistant into a domain expert.
- CLAUDE.md is always loaded into context -- it's your project's permanent background knowledge
- Skills are loaded on demand -- only when Claude detects they're relevant or you invoke them with
/skill-name
This matters because context window space is finite. Skills use a three-level progressive disclosure system:
| Level | What's Loaded | When |
|---|---|---|
| Metadata | Name + description (~100 words) | Always in context |
| SKILL.md body | Full instructions (<5k words) | When skill triggers |
| Bundled resources | References, scripts, assets | Only as needed |
Claude Code originally had two separate systems: slash commands (single .md files in .claude/commands/) and skills (directories in .claude/skills/). As of Claude Code 2.1.3, these have been merged. Skills are now the recommended approach because they support directories with supporting files, YAML frontmatter for behavior control, and automatic discovery.
Your existing .claude/commands/ files continue to work, but skills supersede them.
| Scope | Path | Who Gets It |
|---|---|---|
| Personal | ~/.claude/skills/<name>/SKILL.md |
All your projects |
| Project | .claude/skills/<name>/SKILL.md |
This project (shareable via git) |
| Plugin | <plugin>/skills/<name>/SKILL.md |
Where plugin is enabled |
Every skill needs exactly one file: SKILL.md. It has two parts:
---
# YAML frontmatter (optional but recommended)
name: my-skill
description: What this skill does and when to use it
---
# Markdown body
Your instructions to Claude go here.| Field | Purpose | Example |
|---|---|---|
name |
Display name and / command |
beautiful-react-ui |
description |
When Claude should use this skill | "Use when creating React components with Tailwind and animations" |
allowed-tools |
Tools Claude can use without asking | Read, Grep, Glob, Write, Edit |
context |
Set to fork to run in a subagent |
fork |
agent |
Which subagent to use with context: fork |
Explore, Plan, general-purpose |
disable-model-invocation |
Prevent auto-discovery (manual / only) |
true or false |
user-invocable |
Show in / menu |
true or false |
A skill can be just SKILL.md, or it can be a full directory:
beautiful-react-ui/
SKILL.md # Main instructions (required)
references/ # Detailed docs loaded on demand
tailwind-patterns.md
animation-variants.md
component-anatomy.md
examples/ # Example code
button.tsx
card.tsx
page-section.tsx
scripts/ # Executable scripts
validate-component.sh
Skills support dynamic placeholders:
$ARGUMENTS-- all arguments passed when invoking$ARGUMENTS[0],$1-- specific argument by index!`command`-- runs a shell command and injects its output
Before building our skill, let's understand the patterns we want Claude to follow. This section covers the "knowledge" that goes into the skill.
Each tool has a clear responsibility:
- React -- component structure, state management, data flow
- Tailwind CSS -- visual styling (colors, spacing, typography, layout)
- Framer Motion -- movement and animation (transforms, transitions, gestures)
The key insight: Tailwind handles how things look. Framer Motion handles how things move. They operate on different properties and never conflict.
The cn() function -- every project needs this:
// lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}This combines conditional class logic (clsx) with Tailwind conflict resolution (tailwind-merge). Without it, passing className="bg-red-500" to a component with bg-blue-500 produces unpredictable results.
Class Variance Authority (CVA) -- the standard for variant-based components:
import { cva, type VariantProps } from "class-variance-authority";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md font-medium transition-colors",
{
variants: {
variant: {
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
outline: "border-2 border-primary text-primary",
ghost: "hover:bg-accent hover:text-accent-foreground",
},
size: {
sm: "h-9 px-3 text-sm",
md: "h-10 px-5",
lg: "h-12 px-8 text-lg",
},
},
defaultVariants: { variant: "primary", size: "md" },
}
);Every well-built component follows this structure:
- CVA variant definition
- TypeScript interface extending HTML props +
VariantProps forwardRefwrapper (or directrefprop in React 19+)cn()merge for className override- Headless primitive for accessibility (Radix UI)
const Component = React.forwardRef<HTMLElement, ComponentProps>(
({ className, variant, size, ...props }, ref) => (
<Primitive
ref={ref}
className={cn(componentVariants({ variant, size }), className)}
{...props}
/>
)
);Keep all reusable animations in one file:
// lib/animations.ts
import type { Variants, Transition } from "framer-motion";
export const smoothTransition: Transition = {
duration: 0.5,
ease: [0.17, 0.55, 0.55, 1],
};
export const fadeInUp: Variants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0, transition: smoothTransition },
};
export const staggerContainer: Variants = {
hidden: {},
visible: { transition: { staggerChildren: 0.08 } },
};<motion.div
variants={fadeInUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
className={cn(
"rounded-2xl border bg-card p-6 shadow-sm transition-shadow hover:shadow-lg",
className
)}
>
{children}
</motion.div>Notice: Tailwind classes handle the static styles. Framer Motion's style prop (via animate/whileHover) handles the dynamic transforms. Zero conflict.
src/
components/
ui/ # Primitive components (Button, Card, Input)
animated/ # Animation wrappers (ScrollReveal, PageTransition)
layout/ # Header, Footer, Sidebar, Container
features/ # Feature modules with their own components
hooks/ # Shared custom hooks
lib/
utils.ts # cn() function
animations.ts # Shared Framer Motion variants
styles/
app.css # Tailwind v4 @theme configuration
Now we combine everything into a working skill.
# Personal skill (available in all your projects)
mkdir -p ~/.claude/skills/beautiful-react-ui/references
mkdir -p ~/.claude/skills/beautiful-react-ui/examplescat > ~/.claude/skills/beautiful-react-ui/SKILL.md << 'SKILLEOF'
---
name: beautiful-react-ui
description: >
This skill should be used when the user asks to "create a component",
"build a UI", "add a section", "make it look nice", "add animations",
or when building React components with Tailwind CSS and Framer Motion.
It encodes best practices for beautiful, elegant, clean, and organized
frontend code using the modern React + Tailwind + Framer Motion stack.
allowed-tools: Read, Grep, Glob, Write, Edit
---
# Beautiful React UI — Component Creation Guide
When creating React components, follow these patterns in order.
## 1. Required Utilities
Before creating components, ensure these utilities exist in the project:
### cn() function (lib/utils.ts)
Every component uses `cn()` for class merging. Check if `lib/utils.ts` exists with `cn`. If not, create it:
```ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}Check if lib/animations.ts exists. If not, create it with standard variants.
See references/animation-variants.md for the full set.
Every component MUST follow this anatomy:
- Import section: React, motion (if animated), cn, cva (if variants)
- CVA definition: Base styles + variant map
- TypeScript interface: Extends HTML element props + VariantProps
- Component body: forwardRef wrapper (or direct ref in React 19+)
- cn() merge: Always accept and merge a
classNameprop - Export: Named export + export the variants function
"use client";
import { forwardRef } from "react";
import { motion, type HTMLMotionProps } from "framer-motion";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const componentVariants = cva(
"base-classes-here",
{
variants: {
variant: { default: "...", secondary: "..." },
size: { sm: "...", md: "...", lg: "..." },
},
defaultVariants: { variant: "default", size: "md" },
}
);
interface ComponentProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof componentVariants> {}
const Component = forwardRef<HTMLDivElement, ComponentProps>(
({ className, variant, size, children, ...props }, ref) => (
<div
ref={ref}
className={cn(componentVariants({ variant, size }), className)}
{...props}
>
{children}
</div>
)
);
Component.displayName = "Component";
export { Component, componentVariants };- Use Tailwind classes for ALL visual styling (never inline style for static properties)
- Use
cn()for ALL className construction — never template literals - Never dynamically construct class names (e.g.,
bg-${color}-500). Use complete literal strings with conditional logic - Group classes logically: layout > spacing > sizing > typography > colors > borders > effects
- Use the
grouputility for parent-child hover relationships - For dark mode, use the
dark:variant - Always make components responsive with
sm:,md:,lg:breakpoints
- Import from
framer-motion - Use
motion.div(or appropriate element) only on elements that actually animate - Define reusable variants in
lib/animations.ts, not inline - Use
whileInViewwithviewport={{ once: true }}for scroll-triggered animations - Use
AnimatePresencewithmode="wait"for mount/unmount transitions - Use
layoutIdfor shared layout animations (e.g., tab indicators) - Always respect reduced motion: use
useReducedMotion()hook - Animate transform properties (x, y, scale, rotate) — never layout properties (width, height, left, top)
- Use spring transitions for interactive elements, ease curves for entrance animations
Place files according to this structure:
components/ui/— Primitive components (Button, Card, Input, Badge)components/animated/— Animation wrapper components (ScrollReveal, PageTransition)components/layout/— Layout components (Header, Footer, Container)features/<name>/components/— Feature-specific componentshooks/— Shared custom hookslib/utils.ts— cn() functionlib/animations.ts— Shared animation variants
Before finishing any component, verify:
- Uses
cn()for className merging - Accepts and forwards
classNameprop - Uses
forwardRef(or React 19 ref prop) - Has TypeScript interface extending proper HTML element props
- Has a
displayName - Uses CVA if it has more than one visual variant
- Animation variants are defined in
lib/animations.ts(not inline) - Responsive at sm/md/lg breakpoints
- Respects
prefers-reduced-motion - No dynamic class construction SKILLEOF
### Step 3: Add Reference Files
```bash
cat > ~/.claude/skills/beautiful-react-ui/references/animation-variants.md << 'EOF'
# Standard Animation Variants
These are the reusable animation variants for lib/animations.ts.
## Transitions
```typescript
export const springTransition: Transition = {
type: "spring", stiffness: 400, damping: 30,
};
export const smoothTransition: Transition = {
duration: 0.5, ease: [0.17, 0.55, 0.55, 1],
};
export const fadeIn: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: smoothTransition },
};
export const fadeInUp: Variants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0, transition: smoothTransition },
};
export const fadeInDown: Variants = {
hidden: { opacity: 0, y: -20 },
visible: { opacity: 1, y: 0, transition: smoothTransition },
};
export const fadeInLeft: Variants = {
hidden: { opacity: 0, x: -30 },
visible: { opacity: 1, x: 0, transition: smoothTransition },
};
export const fadeInRight: Variants = {
hidden: { opacity: 0, x: 30 },
visible: { opacity: 1, x: 0, transition: smoothTransition },
};
export const scaleIn: Variants = {
hidden: { opacity: 0, scale: 0.9 },
visible: { opacity: 1, scale: 1, transition: smoothTransition },
};export const staggerContainer: Variants = {
hidden: {},
visible: { transition: { staggerChildren: 0.08, delayChildren: 0.1 } },
};
export const staggerContainerSlow: Variants = {
hidden: {},
visible: { transition: { staggerChildren: 0.15, delayChildren: 0.2 } },
};export const hoverLift = {
whileHover: { y: -4, transition: { duration: 0.2 } },
whileTap: { y: 0 },
};
export const hoverScale = {
whileHover: { scale: 1.03 },
whileTap: { scale: 0.97 },
};EOF
```bash
cat > ~/.claude/skills/beautiful-react-ui/references/component-patterns.md << 'EOF'
# Component Patterns Reference
## Animated Card
```tsx
"use client";
import { motion, type HTMLMotionProps } from "framer-motion";
import { cn } from "@/lib/utils";
import { fadeInUp } from "@/lib/animations";
interface AnimatedCardProps extends HTMLMotionProps<"div"> {
delay?: number;
}
export function AnimatedCard({ className, delay = 0, children, ...props }: AnimatedCardProps) {
return (
<motion.div
variants={fadeInUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.3 }}
transition={{ delay }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
className={cn(
"rounded-2xl border bg-card p-6 shadow-sm transition-shadow hover:shadow-lg",
className
)}
{...props}
>
{children}
</motion.div>
);
}
"use client";
import { motion } from "framer-motion";
import { staggerContainer, fadeInUp } from "@/lib/animations";
interface StaggeredGridProps {
children: React.ReactNode;
className?: string;
}
export function StaggeredGrid({ children, className }: StaggeredGridProps) {
return (
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.2 }}
variants={staggerContainer}
className={cn("grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", className)}
>
{children}
</motion.div>
);
}"use client";
import { motion } from "framer-motion";
import { fadeInUp } from "@/lib/animations";
interface ScrollRevealProps {
children: React.ReactNode;
className?: string;
delay?: number;
}
export function ScrollReveal({ children, className, delay = 0 }: ScrollRevealProps) {
return (
<motion.div
variants={fadeInUp}
initial="hidden"
whileInView="visible"
viewport={{ once: true, amount: 0.3 }}
transition={{ delay }}
className={className}
>
{children}
</motion.div>
);
}"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
export function PageTransition({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
return (
<AnimatePresence mode="wait">
<motion.div
key={pathname}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0, transition: { duration: 0.3 } }}
exit={{ opacity: 0, y: -8, transition: { duration: 0.2 } }}
>
{children}
</motion.div>
</AnimatePresence>
);
}"use client";
import { AnimatePresence, motion } from "framer-motion";
interface ModalProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
}
export function Modal({ isOpen, onClose, children }: ModalProps) {
return (
<AnimatePresence mode="wait">
{isOpen && (
<motion.div
key="modal-backdrop"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
>
<motion.div
key="modal-content"
initial={{ opacity: 0, scale: 0.95, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: 20 }}
transition={{ type: "spring", damping: 25, stiffness: 300 }}
onClick={(e) => e.stopPropagation()}
className="mx-auto mt-20 max-w-lg rounded-2xl bg-white p-6 shadow-xl"
>
{children}
</motion.div>
</motion.div>
)}
</AnimatePresence>
);
}"use client";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
interface Tab {
id: string;
label: string;
}
interface TabBarProps {
tabs: Tab[];
activeId: string;
onChange: (id: string) => void;
}
export function TabBar({ tabs, activeId, onChange }: TabBarProps) {
return (
<div className="flex gap-1 rounded-lg bg-muted p-1">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => onChange(tab.id)}
className={cn(
"relative px-4 py-2 text-sm font-medium transition-colors",
activeId === tab.id ? "text-foreground" : "text-muted-foreground hover:text-foreground"
)}
>
{activeId === tab.id && (
<motion.div
layoutId="active-tab"
className="absolute inset-0 rounded-md bg-background shadow-sm"
transition={{ type: "spring", damping: 30, stiffness: 500 }}
/>
)}
<span className="relative z-10">{tab.label}</span>
</button>
))}
</div>
);
}EOF
### Step 4: Verify the Structure
```bash
# Your skill should look like this:
tree ~/.claude/skills/beautiful-react-ui/
# beautiful-react-ui/
# ├── SKILL.md
# ├── references/
# │ ├── animation-variants.md
# │ └── component-patterns.md
# └── examples/ (optional, add as needed)
Type the slash command in Claude Code:
/beautiful-react-ui Create a pricing card component with three tiers
Claude loads the skill and generates a component following all the patterns: CVA variants for the tiers, cn() for class merging, forwardRef, Framer Motion entrance animation, responsive layout.
Because the skill description includes trigger phrases like "create a component" and "build a UI", Claude will automatically load it when you say things like:
> Build a hero section with a headline, subtitle, CTA button, and a background gradient
> Create a dashboard sidebar with navigation items and an animated active indicator
> Make a testimonial carousel with smooth transitions
Claude matches your request against the skill description and loads the instructions before generating code.
To share the skill with your team, put it in the project:
mkdir -p .claude/skills/beautiful-react-ui/references
# Copy the SKILL.md and references/ into .claude/skills/beautiful-react-ui/
git add .claude/skills/beautiful-react-ui/
git commit -m "Add beautiful-react-ui skill for consistent component patterns"Now every team member using Claude Code on this project gets the same component patterns.
Add context: fork to run the skill in an isolated subagent. The parent conversation stays clean while the subagent does heavy work:
---
name: beautiful-react-ui
context: fork
agent: general-purpose
allowed-tools: Read, Grep, Glob, Write, Edit
description: ...
---With context: fork, invoking the skill spawns a separate agent that reads your codebase, generates the component, writes the file, and returns only the final result to your main conversation.
Use backtick commands to inject project-specific data:
---
name: beautiful-react-ui
description: ...
---
## Project Context
- Package.json dependencies: !`cat package.json | jq '.dependencies'`
- Existing components: !`ls src/components/ui/ 2>/dev/null`
- Tailwind config: !`cat tailwind.config.ts 2>/dev/null || cat src/styles/app.css 2>/dev/null`This tells Claude what's already in the project before it starts generating code.
You can define lifecycle hooks scoped to the skill:
---
name: beautiful-react-ui
hooks:
PostToolUse:
- matcher: Write
command: "npx prettier --write $FILE_PATH"
---This auto-formats every file Claude writes while the skill is active.
- Create a test project with React + Tailwind + Framer Motion set up
- Invoke the skill with various prompts:
- "Create a button component" (simple)
- "Build a feature grid with 6 cards and staggered animation" (complex)
- "Create a modal with backdrop blur" (animation-heavy)
- Check the output against the quality checklist in the skill
- Iterate on the SKILL.md when patterns are wrong or missing
| Problem | Fix in SKILL.md |
|---|---|
| Claude uses inline styles instead of Tailwind | Add explicit rule: "Never use inline style for static visual properties" |
| Animations defined inline instead of in lib/ | Add rule: "Always check lib/animations.ts first, add new variants there" |
| Missing forwardRef | Add template with forwardRef as the required pattern |
| No dark mode support | Add rule: "Always include dark: variants for colors and backgrounds" |
| Components not responsive | Add rule: "Always use sm:/md:/lg: breakpoints" |
A good skill should produce code where:
- You rarely need to edit the generated output
- The code follows your team's conventions automatically
- New team members get consistent output without reading a style guide
- Components are accessible, responsive, and animated by default
Skills follow the Agent Skills open standard (agentskills.io), originally developed by Anthropic and released as an open standard. The format is supported by multiple AI tools: Cursor, VS Code, Gemini CLI, OpenAI Codex, and others.
Skills transform Claude from a general-purpose assistant into a specialized one by providing procedural knowledge -- company-specific schemas, domain workflows, repeatable procedures, and bundled scripts.
The progressive disclosure system works in three levels:
- Metadata (name + description, ~100 words) -- always in context, used for relevance matching
- SKILL.md body (instructions, <5k words) -- loaded when the skill triggers
- Bundled resources (references, scripts, assets) -- loaded only as needed by Claude
Originally two separate systems:
- Slash commands: Single
.mdfiles in.claude/commands/, invoked with/command-name - Skills: Directories with
SKILL.mdplus optional files in.claude/skills/
As of Claude Code 2.1.3, slash commands merged into the skills system. Existing command files continue to work, but skills are recommended because they support:
- Directories with supporting files
- YAML frontmatter for behavior control
- Automatic discovery (not just manual invocation)
- If a skill and command share a name, the skill takes precedence
| Field | Required | Type | Description |
|---|---|---|---|
name |
No | string | Display name / slash-command. Lowercase, numbers, hyphens only (max 64 chars). Default: directory name |
description |
Recommended | string | When Claude should use this. Max 1024 characters. Third person, specific trigger phrases |
argument-hint |
No | string | Autocomplete hint, e.g., [issue-number] |
disable-model-invocation |
No | boolean | true = only manual /name invocation. Default: false |
user-invocable |
No | boolean | false = hidden from / menu (background knowledge only). Default: true |
allowed-tools |
No | string | Tools without permission prompts, e.g., Read, Grep, Glob or Bash(git *) |
model |
No | string | Override model for this skill |
context |
No | string | Set to fork for isolated subagent execution |
agent |
No | string | Subagent type: Explore, Plan, general-purpose, or custom |
hooks |
No | object | Lifecycle hooks (PreToolUse, PostToolUse, Stop) scoped to this skill |
| Scope | Path | Priority |
|---|---|---|
| Enterprise | Managed settings | Highest |
| Personal | ~/.claude/skills/<name>/SKILL.md |
High |
| Project | .claude/skills/<name>/SKILL.md |
Medium |
| Plugin | <plugin>/skills/<name>/SKILL.md |
Namespaced (no conflict) |
Monorepo support: Claude auto-discovers skills from nested .claude/skills/ directories.
- Direct: Type
/skill-name [arguments]in Claude Code - Automatic: Claude matches your request to skill descriptions and loads relevant ones
- Background-only: Set
user-invocable: false-- Claude uses it but it's hidden from/menu - Subagent: Set
context: fork-- runs in isolated agent, returns only results
String substitutions:
$ARGUMENTS-- all arguments$ARGUMENTS[N]or$N-- specific argument${CLAUDE_SESSION_ID}-- session ID
Shell injection: !`command` runs shell commands before content is sent to Claude
Permission control:
Skill(commit) # Allow specific skill
Skill(review-pr *) # Allow with any arguments
Skill(deploy *) # Deny specific skill
Skill # Deny all skills
Description quality is critical -- Claude uses semantic matching. Include specific trigger phrases:
# Good
description: >
Use when the user asks to "create a component", "build a UI",
"add animations", or when working with React + Tailwind + Framer Motion.
# Bad
description: Provides guidance for UI development.Keep SKILL.md concise: Target 1,500-2,000 words. Move detail to references/.
Writing style: Use imperative form ("Parse the frontmatter"), third person in descriptions ("This skill should be used when..."). Avoid "you should."
Naming: Use gerund form (building-components, analyzing-code). Lowercase, numbers, hyphens only.
Feedback loops: Include validation steps in the skill (run linter, check output, fix errors).
Avoid:
- Deeply nested references (keep one level deep)
- Time-sensitive information
- Offering too many options (provide a default)
- Vague names like
helper,utils,tools
- Extend Claude with Skills: https://code.claude.com/docs/en/skills
- Skill Best Practices: https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices
- Agent Skills Standard: https://agentskills.io
- Example Skills Repo: https://github.com/anthropics/skills
- Create Custom Subagents: https://code.claude.com/docs/en/sub-agents
- Claude Code Plugins: https://code.claude.com/docs/en/plugins
- awesome-claude-skills (travisvn): https://github.com/travisvn/awesome-claude-skills
- awesome-agent-skills (VoltAgent): https://github.com/VoltAgent/awesome-agent-skills
- awesome-claude-code (hesreallyhim): https://github.com/hesreallyhim/awesome-claude-code
- Claude Code Customization Guide (alexop.dev): https://alexop.dev/posts/claude-code-customization-guide-claudemd-skills-subagents/
- Claude Code Skills Deep Dive (Mikhail Shilkov): https://mikhail.io/2025/10/claude-code-skills/
- Agent Skills First Principles (Lee Hanchung): https://leehanchung.github.io/blogs/2025/10/26/claude-skills-deep-dive/
Component organization: Feature-based structure with colocation.
src/
features/
auth/
components/
hooks/
services/
types.ts
dashboard/
components/
hooks/
Shared components go in src/components/, feature-specific ones stay inside the feature folder. Hooks used by more than one feature go in src/hooks/.
Server Components vs Client Components (Next.js App Router):
- Default to Server Components for static content, data fetching, SEO
- Use
"use client"for: state, effects, event handlers, browser APIs, Framer Motion - Composition pattern: Pass Server Components as children to Client Components
- The
"use client"directive only needs to be at the boundary file
React 19+ eliminates forwardRef -- ref is now a regular prop:
function Button({ ref, ...props }: ButtonProps) {
return <button ref={ref} {...props} />;
}The cn() utility is foundational. Combines clsx (conditional logic) with tailwind-merge (conflict resolution). Every component should use it.
CVA (Class Variance Authority) is the standard for multi-variant components. Defines base styles + variant map in a declarative structure. Used by shadcn/ui for every component.
Tailwind v4 changes: Configuration moves from tailwind.config.js to CSS:
@import "tailwindcss";
@theme {
--color-primary: oklch(0.55 0.2 260);
--font-sans: "Inter", system-ui, sans-serif;
--radius-lg: 0.75rem;
}Custom utilities with @utility directive:
@utility glass-card {
backdrop-blur-xl bg-white/10 border border-white/20 rounded-2xl;
}Custom variants with @variant:
@variant hocus (&:hover, &:focus-visible);Key rules:
- Never dynamically construct class names (
bg-${color}-500) - Use
@applysparingly (v4 recommends component extraction instead) - Use the
grouputility for parent-child hover relationships - Install
prettier-plugin-tailwindcssfor consistent class ordering
Rebranded to Motion (package: motion), same API. Import from "framer-motion" or "motion".
Reusable variants: Define in a shared file, reference by name. Variant propagation means children inherit variant names from parents.
Key patterns:
whileInView+viewport={{ once: true }}for scroll animationsuseScroll+useTransformfor scroll-linked parallaxAnimatePresence mode="wait"for mount/unmountlayoutIdfor shared layout animations (tab indicators, list reordering)whileHover/whileTapfor gesture feedback
Performance rules:
- Animate transform properties (x, y, scale, rotate) -- GPU-accelerated
- Never animate layout properties (width, height, left, top) -- causes reflow
- Use
motion.divonly on elements that actually animate - Respect accessibility with
useReducedMotion()
Core rule: Tailwind handles how things look (classes). Framer Motion handles how things move (style transforms). They operate on different properties and never conflict.
The pattern: Tailwind classes go in className. Framer Motion properties go in animate/initial/exit/whileHover props.
| Library | Focus |
|---|---|
| shadcn/ui | Copy-paste components, Radix UI + Tailwind + CVA |
| Aceternity UI | Animated components for landing pages |
| Hover.dev | 20+ prebuilt animations for React + Tailwind + Framer |
| Magic UI | Animated components for marketing sites |
| DynaUI | Full animated component library |
React patterns:
- React Folder Structure (Robin Wieruch): https://www.robinwieruch.de/react-folder-structure/
- Server and Client Components (Next.js): https://nextjs.org/docs/app/getting-started/server-and-client-components
- React TypeScript forwardRef (Total TypeScript): https://www.totaltypescript.com/forwardref-with-generic-components
- React Stack Patterns: https://www.patterns.dev/react/react-2026/
Tailwind CSS:
- Tailwind Best Practices (Infinum Handbook): https://infinum.com/handbook/frontend/react/tailwind/best-practices
- Tailwind CSS Best Practices 2025-2026 (FrontendTools): https://www.frontendtools.tech/blog/tailwind-css-best-practices-design-system-patterns
- Tailwind CSS v4 Tips (Nikolai Lehbrink): https://www.nikolailehbr.ink/blog/tailwindcss-v4-tips/
- CVA Documentation: https://cva.style/docs
Framer Motion:
- Framer Motion + Tailwind 2025 Stack (DEV Community): https://dev.to/manukumar07/framer-motion-tailwind-the-2025-animation-stack-1801
- Advanced Animation Patterns (Maxime Heckel): https://blog.maximeheckel.com/posts/advanced-animation-patterns-with-framer-motion/
- Mastering Framer Motion (Luxis Design): https://www.luxisdesign.io/blog/mastering-framer-motion-advanced-animation-techniques-for-2025
- Motion Documentation: https://motion.dev/docs/react-motion-component
Combined stack:
- Anatomy of shadcn/ui (Manupa.dev): https://manupa.dev/blog/anatomy-of-shadcn-ui
- shadcn/ui Documentation: https://ui.shadcn.com/docs
- Hover.dev Components: https://www.hover.dev/components
- Aceternity UI: https://www.aceternity.com/components
Tutorial created on February 5, 2026. Based on research of official Anthropic documentation, the Agent Skills specification, and current best practices for the React + Tailwind CSS + Framer Motion stack.