Claude-skill-registry component-aesthetic-checker

Validates shadcn/ui component customization depth, ensuring components aren't used with default props and checking for consistent design system implementation across Tanstack Start applications

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/component-aesthetic-checker" ~/.claude/skills/majiayu000-claude-skill-registry-component-aesthetic-checker && rm -rf "$T"
manifest: skills/data/component-aesthetic-checker/SKILL.md
source content

Component Aesthetic Checker SKILL

Activation Patterns

This SKILL automatically activates when:

  • shadcn/ui components (
    Button
    ,
    Card
    ,
    Input
    , etc.) are used in
    .react
    files
  • Component props are added or modified
  • The
    ui
    prop is customized for component variants
  • Design system tokens are referenced in components
  • Multiple components are refactored together
  • Before component library updates

Expertise Provided

Component Customization Depth Analysis

  • Default Prop Detection: Identifies components using only default values
  • UI Prop Validation: Ensures
    ui
    prop is used for deep customization
  • Design System Consistency: Validates consistent pattern usage across components
  • Spacing Patterns: Checks for proper Tailwind spacing scale usage
  • Icon Usage: Validates consistent icon library and sizing
  • Loading States: Ensures async components have loading feedback

Specific Checks Performed

❌ Critical Issues (Insufficient Customization)

<!-- These patterns trigger alerts: -->

<!-- Using default props only -->
<Button onClick="submit">Submit</Button>

<!-- No UI prop customization -->
<Card>
  <p>Content</p>
</Card>

<!-- Inconsistent spacing -->
<div className="p-4">  <!-- Random spacing values -->
  <Button className="mt-3 ml-2">Action</Button>
</div>

<!-- Missing loading states -->
<Button onClick="asyncAction">Save</Button>  <!-- No :loading prop -->

✅ Correct Customized Patterns

<!-- These patterns are validated as correct: -->

<!-- Deep customization with ui prop -->
<Button
  color="brand-coral"
  size="lg"
  variant="solid"
  :ui="{
    font: 'font-heading',
    rounded: 'rounded-full',
    padding: { lg: 'px-8 py-4' }
  }"
  loading={isSubmitting"
  className="transition-all duration-300 hover:scale-105"
  onClick="submit"
>
  Submit
</Button>

<!-- Fully customized card -->
<Card
  :ui="{
    background: 'bg-white dark:bg-brand-midnight',
    ring: 'ring-1 ring-brand-coral/20',
    rounded: 'rounded-2xl',
    shadow: 'shadow-xl',
    body: { padding: 'p-8' },
    header: { padding: 'px-8 pt-8 pb-4' }
  }"
  className="transition-shadow duration-300 hover:shadow-2xl"
>
  <template #header>
    <h3 className="font-heading text-2xl">Title</h3>
  <p className="text-gray-700 dark:text-gray-300">Content</p>
</Card>

<!-- Consistent spacing (Tailwind scale) -->
<div className="p-6 space-y-4">
  <Button className="mt-4">Action</Button>
</div>

<!-- Proper loading state -->
<Button
  loading={isSubmitting"
  disabled={isSubmitting"
  onClick="asyncAction"
>
  { isSubmitting ? 'Saving...' : 'Save'}
</Button>

Integration Points

Complementary to Existing Components

  • tanstack-ui-architect agent: Handles component selection and API guidance, SKILL validates implementation
  • frontend-design-specialist agent: Provides design direction, SKILL enforces consistency
  • shadcn-ui-design-validator: Catches generic patterns, SKILL ensures deep customization

Escalation Triggers

  • Component API questions →
    tanstack-ui-architect
    agent (with MCP lookup)
  • Design consistency issues →
    frontend-design-specialist
    agent
  • Complex component composition →
    /es-component
    command
  • Full component audit →
    /es-design-review
    command

Validation Rules

P1 - Critical (Default Component Usage)

  • No UI Prop Customization: Using shadcn/ui components without
    ui
    prop
  • All Default Props: No color, size, variant, or other prop customizations
  • Missing Loading States: Async actions without
    :loading
    prop
  • No Hover States: Interactive components without hover feedback
  • Inconsistent Patterns: Same component with wildly different customizations

P1 - Critical (Distributional Convergence Anti-Patterns)

These patterns indicate generic "AI-generated" aesthetics and MUST be flagged:

Font Anti-Patterns (Auto-Detect)

// ❌ CRITICAL: Generic fonts that dominate 80%+ of websites
fontFamily: {
  sans: ['Inter', ...]        // Flag: "Inter is overused - consider Space Grotesk, Plus Jakarta Sans"
  sans: ['Roboto', ...]       // Flag: "Roboto is overused - consider IBM Plex Sans, Outfit"
  sans: ['Open Sans', ...]    // Flag: "Open Sans is generic - consider Satoshi, General Sans"
  sans: ['system-ui', ...]    // Flag: Only acceptable as fallback, not primary
}

// ❌ CRITICAL: Default Tailwind font classes without customization
className="font-sans"         // Flag if font-sans maps to Inter/Roboto
className="text-base"         // Flag: Generic sizing, consider custom scale

Recommended Font Alternatives (suggest these in reports):

  • Body: Space Grotesk, Plus Jakarta Sans, IBM Plex Sans, Outfit, Satoshi
  • Headings: Archivo Black, Cabinet Grotesk, Clash Display, General Sans
  • Mono: JetBrains Mono, Fira Code, Source Code Pro

Color Anti-Patterns (Auto-Detect)

// ❌ CRITICAL: Purple gradients (most common AI aesthetic)
className="bg-gradient-to-r from-purple-500 to-purple-600"
className="bg-gradient-to-r from-violet-500 to-purple-500"
className="bg-purple-600"
className="text-purple-500"

// ❌ CRITICAL: Default gray backgrounds without brand treatment
className="bg-gray-50"        // Flag: "Consider brand-tinted background"
className="bg-white"          // Flag: "Consider atmospheric gradient or texture"
className="bg-slate-100"      // Flag if used extensively without brand colors

Recommended Color Approaches (suggest these in reports):

  • Use CSS variables with brand palette (
    --brand-primary
    ,
    --brand-accent
    )
  • Tint grays with brand color:
    bg-brand-gray-50
    instead of
    bg-gray-50
  • Gradients: Use brand colors, not default purple
  • Atmospheric: Layer gradients with subtle brand tints

Animation Anti-Patterns (Auto-Detect)

// ❌ CRITICAL: No transitions on interactive elements
<Button>Click</Button>        // Flag: "Add transition-all duration-300"
<Card>Content</Card>          // Flag: "Add hover:shadow-lg transition"

// ❌ CRITICAL: Only basic hover without micro-interactions
className="hover:bg-blue-600" // Flag: "Consider hover:scale-105 or hover:-translate-y-1"

Detection Rules (implement in validation):

// Font detection
const OVERUSED_FONTS = ['Inter', 'Roboto', 'Open Sans', 'Helvetica', 'Arial'];
const hasBadFont = (config) => OVERUSED_FONTS.some(f =>
  config.fontFamily?.sans?.includes(f)
);

// Purple gradient detection
const PURPLE_PATTERN = /(?:purple|violet)-[4-6]00/;
const hasPurpleGradient = (className) =>
  className.includes('gradient') && PURPLE_PATTERN.test(className);

// Missing animation detection
const INTERACTIVE_COMPONENTS = ['Button', 'Card', 'Link', 'Input'];
const hasNoTransition = (className) =>
  !className.includes('transition') && !className.includes('animate');

P2 - Important (Design System Consistency)

  • Random Spacing Values: Not using Tailwind spacing scale (p-4, mt-6, etc.)
  • Inconsistent Icon Sizing: Icons with different sizes in similar contexts
  • Mixed Color Approaches: Some components use theme colors, others use arbitrary values
  • Incomplete Dark Mode: Dark mode variants missing on customized components
  • No Focus States: Interactive elements without focus-visible styling

P3 - Polish (Enhanced UX)

  • Limited Prop Usage: Only using 1-2 props when more would improve UX
  • No Micro-interactions: Missing subtle animations on state changes
  • Generic Variants: Using 'solid', 'outline' without brand customization
  • Underutilized UI Prop: Not customizing padding, rounded, shadow in ui prop
  • Missing Icons: Buttons/actions without supporting icons for clarity

Remediation Examples

Fixing Default Component Usage

<!-- ❌ Critical: Default props only -->
  <Button onClick="handleClick">
    Click me
  </Button>

<!-- ✅ Correct: Deep customization -->
  <Button
    color="primary"
    size="lg"
    variant="solid"
    icon="i-heroicons-sparkles"
    :ui="{
      font: 'font-heading tracking-wide',
      rounded: 'rounded-full',
      padding: { lg: 'px-8 py-4' },
      shadow: 'shadow-lg hover:shadow-xl'
    }"
    className="transition-all duration-300 hover:scale-105 active:scale-95"
    onClick="handleClick"
  >
    Click me
  </Button>

Fixing Missing Loading States

<!-- ❌ Critical: No loading feedback -->
const handleSubmit = async () => {
  await submitForm();
};

  <Button onClick="handleSubmit">
    Submit Form
  </Button>

<!-- ✅ Correct: Proper loading state -->
const isSubmitting = ref(false);

const handleSubmit = async () => {
  isSubmitting.value = true;
  try {
    await submitForm();
  } finally {
    isSubmitting.value = false;
  }
};

  <Button
    loading={isSubmitting"
    disabled={isSubmitting"
    onClick="handleSubmit"
  >
    <span className="flex items-center gap-2">
      <Icon
        {&& "!isSubmitting"
        name="i-heroicons-paper-airplane"
      />
      { isSubmitting ? 'Submitting...' : 'Submit Form'}
    </span>
  </Button>

Fixing Inconsistent Spacing

<!-- ❌ P2: Random spacing values -->
  <div className="p-3">
    <Card className="mt-5 ml-7">
      <div className="p-2">
        <Button className="mt-3.5">Action</Button>
      </div>
    </Card>
  </div>

<!-- ✅ Correct: Tailwind spacing scale -->
  <div className="p-4">
    <Card className="mt-4">
      <div className="p-6 space-y-4">
        <Button>Action</Button>
      </div>
    </Card>
  </div>

<!-- Using consistent spacing: 4, 6, 8, 12, 16 (Tailwind scale) -->

Fixing Design System Inconsistency

<!-- ❌ P2: Inconsistent component styling -->
  <div>
    <!-- Button 1: Heavily customized -->
    <Button
      color="primary"
      :ui="{ rounded: 'rounded-full', shadow: 'shadow-xl' }"
    >
      Action 1
    </Button>

    <!-- Button 2: Default (inconsistent!) -->
    <Button>Action 2</Button>

    <!-- Button 3: Different customization pattern -->
    <Button color="red" size="xs">
      Action 3
    </Button>
  </div>

<!-- ✅ Correct: Consistent design system -->
// Define reusable button variants
const buttonVariants = {
  primary: {
    color: 'primary',
    size: 'lg',
    ui: {
      rounded: 'rounded-full',
      shadow: 'shadow-lg hover:shadow-xl',
      font: 'font-heading'
    },
    class: 'transition-all duration-300 hover:scale-105'
  },
  secondary: {
    color: 'gray',
    size: 'md',
    variant: 'outline',
    ui: {
      rounded: 'rounded-lg',
      font: 'font-sans'
    },
    class: 'transition-colors duration-200'
  }
};

  <div className="space-x-4">
    <Button v-bind="buttonVariants.primary">
      Action 1
    </Button>

    <Button v-bind="buttonVariants.primary">
      Action 2
    </Button>

    <Button v-bind="buttonVariants.secondary">
      Action 3
    </Button>
  </div>

Fixing Underutilized UI Prop

<!-- ❌ P3: Not using ui prop for customization -->
  <Card className="rounded-2xl shadow-xl p-8">
    <p>Content</p>
  </Card>

<!-- ✅ Correct: Proper ui prop usage -->
  <Card
    :ui="{
      rounded: 'rounded-2xl',
      shadow: 'shadow-xl hover:shadow-2xl',
      body: {
        padding: 'p-8',
        background: 'bg-white dark:bg-brand-midnight'
      },
      ring: 'ring-1 ring-brand-coral/20'
    }"
    className="transition-shadow duration-300"
  >
    <p className="text-gray-700 dark:text-gray-300">Content</p>
  </Card>

MCP Server Integration

When shadcn/ui MCP server is available:

Component Prop Validation

// Before validating customization depth, get actual component API
const componentDocs = await mcp.shadcn.get_component("Button");

// Validate that used props exist
// componentDocs.props: ['color', 'size', 'variant', 'icon', 'loading', 'disabled', ...]

// Check for underutilized props
const usedProps = ['color', 'size']; // From component code
const availableProps = componentDocs.props;
const unutilizedProps = availableProps.filter(p => !usedProps.includes(p));

// Suggest: "Consider using 'icon' or 'loading' props for richer UX"

UI Prop Structure Validation

// Validate ui prop structure against schema
const uiSchema = componentDocs.ui_schema;

// User code: :ui="{ font: 'font-heading', rounded: 'rounded-full' }"
// Validate: Are 'font' and 'rounded' valid keys in ui prop?
// Suggest: Other available ui customizations (padding, shadow, etc.)

Consistency Across Components

// Check multiple component instances
const buttonInstances = findAllComponents("Button");

// Analyze customization patterns
// Flag: Component used with 5 different customization styles
// Suggest: Create composable or variant system for consistency

Benefits

Immediate Impact

  • Prevents Generic Appearance: Ensures components are branded, not defaults
  • Enforces Design Consistency: Catches pattern drift across components
  • Improves User Feedback: Validates loading states and interactions
  • Educates on Component API: Shows developers full customization capabilities

Long-term Value

  • Consistent Component Library: All components follow design system
  • Faster Component Development: Clear patterns and examples
  • Better Code Maintainability: Reusable component variants
  • Reduced Visual Debt: Prevents accumulation of one-off styles

Usage Examples

During Component Usage

// Developer adds: <Button>Click me</Button>
// SKILL immediately activates: "⚠️ P1: Button using all default props. Customize with color, size, variant, and ui prop for brand distinctiveness."

During Async Actions

// Developer creates async button: <Button onClick="submitForm">Submit</Button>
// SKILL immediately activates: "⚠️ P1: Button triggers async action but lacks :loading prop. Add loading state for user feedback."

During Refactoring

// Developer adds 5th different button style
// SKILL immediately activates: "⚠️ P2: Button used with 5 different customization patterns. Consider creating reusable variants for consistency."

Before Deployment

// SKILL runs comprehensive check: "✅ Component aesthetic validation passed. 23 components with deep customization, consistent patterns, and proper loading states detected."

Design System Maturity Levels

Level 0: Defaults Only (Avoid)

<Button>Action</Button>
<Card><p>Content</p></Card>
<Input value="value" />

Issues: Generic appearance, no brand identity, inconsistent with custom design

Level 1: Basic Props (Minimum)

<Button color="primary" size="lg">Action</Button>
<Card className="shadow-lg"><p>Content</p></Card>
<Input value="value" placeholder="Enter value" />

Better: Some customization, but limited depth

Level 2: UI Prop + Classes (Target)

<Button
  color="primary"
  size="lg"
  :ui="{ rounded: 'rounded-full', font: 'font-heading' }"
  className="transition-all duration-300 hover:scale-105"
>
  Action
</Button>

<Card
  :ui="{
    background: 'bg-white dark:bg-brand-midnight',
    ring: 'ring-1 ring-brand-coral/20',
    shadow: 'shadow-xl'
  }"
>
  <p>Content</p>
</Card>

Ideal: Deep customization, brand-distinctive, consistent patterns

Level 3: Design System (Advanced)

<!-- Reusable variants from composables -->
<Button v-bind="designSystem.button.variants.primary">
  Action
</Button>

<Card v-bind="designSystem.card.variants.elevated">
  <p>Content</p>
</Card>

Advanced: Centralized design system, maximum consistency

Component Customization Checklist

For each shadcn/ui component, validate:

  • Props: Uses at least 2-3 props (color, size, variant, etc.)
  • UI Prop: Includes
    ui
    prop for deep customization (rounded, font, padding, shadow)
  • Classes: Adds Tailwind utilities for animations and effects
  • Loading State: Async actions have
    :loading
    and
    :disabled
    props
  • Icons: Includes relevant icons for clarity (
    :icon
    prop or slot)
  • Hover State: Interactive elements have hover feedback
  • Focus State: Keyboard navigation has visible focus styles
  • Dark Mode: Includes dark mode variants in
    ui
    prop
  • Spacing: Uses Tailwind spacing scale (4, 6, 8, 12, 16)
  • Consistency: Follows same patterns as other instances

This SKILL ensures every shadcn/ui component is deeply customized, consistently styled, and provides excellent user feedback, preventing the default/generic appearance that makes AI-generated UIs immediately recognizable.