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
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
/plugin marketplace add hirefrank/hirefrank-marketplace/plugin install edge-stack@hirefrank-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This SKILL automatically activates when:
Button, Card, Input, etc.) are used in .react filesui prop is customized for component variantsui prop is used for deep 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 -->
<!-- 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>
tanstack-ui-architect agent (with MCP lookup)frontend-design-specialist agent/es-component command/es-design-review commandui prop:loading propThese patterns indicate generic "AI-generated" aesthetics and MUST be flagged:
// ❌ 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):
// ❌ 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):
--brand-primary, --brand-accent)bg-brand-gray-50 instead of bg-gray-50// ❌ 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');
<!-- ❌ 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>
<!-- ❌ 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>
<!-- ❌ 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) -->
<!-- ❌ 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>
<!-- ❌ 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>
When shadcn/ui MCP server is available:
// 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"
// 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.)
// 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
// 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."
// 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."
// Developer adds 5th different button style
// SKILL immediately activates: "⚠️ P2: Button used with 5 different customization patterns. Consider creating reusable variants for consistency."
// SKILL runs comprehensive check: "✅ Component aesthetic validation passed. 23 components with deep customization, consistent patterns, and proper loading states detected."
<Button>Action</Button>
<Card><p>Content</p></Card>
<Input value="value" />
Issues: Generic appearance, no brand identity, inconsistent with custom design
<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
<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
<!-- 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
For each shadcn/ui component, validate:
ui prop for deep customization (rounded, font, padding, shadow):loading and :disabled props:icon prop or slot)ui propThis 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.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.