Skip to content

Instantly share code, notes, and snippets.

@swapp1990
Created February 6, 2026 03:35
Show Gist options
  • Select an option

  • Save swapp1990/44a9c1901b81f3bfea824d86cdc3ff34 to your computer and use it in GitHub Desktop.

Select an option

Save swapp1990/44a9c1901b81f3bfea824d86cdc3ff34 to your computer and use it in GitHub Desktop.
Output from task run-1770348311953

Building a Claude Code Skill for Modern React UI Development

A Complete Tutorial: From Skill Basics to a Production-Ready "Beautiful UI" Skill


Table of Contents

  1. Introduction
  2. What Are Claude Code Skills?
  3. Anatomy of a Skill
  4. The Modern React + Tailwind + Framer Motion Stack
  5. Building the Skill: Step by Step
  6. Using the Skill in a Project
  7. Advanced Skill Features
  8. Testing and Iterating
  9. Appendix A: Claude Code Skills Research
  10. Appendix B: React + Tailwind + Framer Motion Research

1. Introduction

This tutorial teaches you two things at once:

  1. How to create a Claude Code skill -- a reusable package of instructions that extends Claude's capabilities
  2. 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.

Who This Is For

  • 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

Prerequisites

  • Claude Code installed and working
  • Basic familiarity with React, Tailwind CSS, and component-based development

2. What Are Claude Code Skills?

The Core Idea

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.

How They Differ from CLAUDE.md

  • 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

Historical Context

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.

Where Skills Live

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

3. Anatomy of a Skill

The Required File: SKILL.md

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.

Frontmatter Fields

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

Directory Structure

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

String Substitutions

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

4. The Modern React + Tailwind + Framer Motion Stack

Before building our skill, let's understand the patterns we want Claude to follow. This section covers the "knowledge" that goes into the skill.

4.1 The Three-Tool Division

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.

4.2 Essential Utilities

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" },
  }
);

4.3 The Component Anatomy Pattern

Every well-built component follows this structure:

  1. CVA variant definition
  2. TypeScript interface extending HTML props + VariantProps
  3. forwardRef wrapper (or direct ref prop in React 19+)
  4. cn() merge for className override
  5. 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}
    />
  )
);

4.4 Centralized Animation Variants

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 } },
};

4.5 Combining Tailwind with Framer Motion

<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.

4.6 Project Structure

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

5. Building the Skill: Step by Step

Now we combine everything into a working skill.

Step 1: Create the Directory

# Personal skill (available in all your projects)
mkdir -p ~/.claude/skills/beautiful-react-ui/references
mkdir -p ~/.claude/skills/beautiful-react-ui/examples

Step 2: Write the SKILL.md

cat > ~/.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));
}

Animation variants (lib/animations.ts)

Check if lib/animations.ts exists. If not, create it with standard variants. See references/animation-variants.md for the full set.

2. Component Creation Pattern

Every component MUST follow this anatomy:

  1. Import section: React, motion (if animated), cn, cva (if variants)
  2. CVA definition: Base styles + variant map
  3. TypeScript interface: Extends HTML element props + VariantProps
  4. Component body: forwardRef wrapper (or direct ref in React 19+)
  5. cn() merge: Always accept and merge a className prop
  6. Export: Named export + export the variants function

Template:

"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 };

3. Tailwind Rules

  • 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 group utility for parent-child hover relationships
  • For dark mode, use the dark: variant
  • Always make components responsive with sm:, md:, lg: breakpoints

4. Animation Rules

  • 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 whileInView with viewport={{ once: true }} for scroll-triggered animations
  • Use AnimatePresence with mode="wait" for mount/unmount transitions
  • Use layoutId for 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

5. File Organization

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 components
  • hooks/ — Shared custom hooks
  • lib/utils.ts — cn() function
  • lib/animations.ts — Shared animation variants

6. Quality Checklist

Before finishing any component, verify:

  • Uses cn() for className merging
  • Accepts and forwards className prop
  • 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],
};

Entrance Variants

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 },
};

Container Variants

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 } },
};

Interactive Variants

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>
  );
}

Staggered Grid

"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>
  );
}

Scroll Reveal Wrapper

"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>
  );
}

Page Transition

"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>
  );
}

Modal with 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>
  );
}

Tab Bar with Layout Animation

"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)

6. Using the Skill in a Project

Direct Invocation

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.

Automatic Invocation

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.

In a Team Project

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.


7. Advanced Skill Features

Running in a Subagent

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.

Dynamic Context Injection

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.

Hooks in Skills

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.


8. Testing and Iterating

Test Strategy

  1. Create a test project with React + Tailwind + Framer Motion set up
  2. 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)
  3. Check the output against the quality checklist in the skill
  4. Iterate on the SKILL.md when patterns are wrong or missing

Common Issues and Fixes

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"

Measuring Success

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

Appendix A: Claude Code Skills Research

A.1 What Are Skills (Detailed)

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:

  1. Metadata (name + description, ~100 words) -- always in context, used for relevance matching
  2. SKILL.md body (instructions, <5k words) -- loaded when the skill triggers
  3. Bundled resources (references, scripts, assets) -- loaded only as needed by Claude

A.2 Skills vs. Slash Commands

Originally two separate systems:

  • Slash commands: Single .md files in .claude/commands/, invoked with /command-name
  • Skills: Directories with SKILL.md plus 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

A.3 Complete Frontmatter Reference

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

A.4 Skill Storage Locations

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.

A.5 Invocation Methods

  1. Direct: Type /skill-name [arguments] in Claude Code
  2. Automatic: Claude matches your request to skill descriptions and loads relevant ones
  3. Background-only: Set user-invocable: false -- Claude uses it but it's hidden from / menu
  4. Subagent: Set context: fork -- runs in isolated agent, returns only results

A.6 Dynamic Features

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

A.7 Best Practices Summary

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

A.8 Official Resources

A.9 Community Resources


Appendix B: React + Tailwind + Framer Motion Research

B.1 Modern React Patterns (2025-2026)

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} />;
}

B.2 Tailwind CSS Best Practices

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 @apply sparingly (v4 recommends component extraction instead)
  • Use the group utility for parent-child hover relationships
  • Install prettier-plugin-tailwindcss for consistent class ordering

B.3 Framer Motion Best Practices

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 animations
  • useScroll + useTransform for scroll-linked parallax
  • AnimatePresence mode="wait" for mount/unmount
  • layoutId for shared layout animations (tab indicators, list reordering)
  • whileHover/whileTap for 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.div only on elements that actually animate
  • Respect accessibility with useReducedMotion()

B.4 Combining the Stack

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.

B.5 Component Libraries Using This Stack

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

B.6 Sources

React patterns:

Tailwind CSS:

Framer Motion:

Combined stack:


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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment