--- name: create-component description: Create reusable components using TailwindCSS utilities with proper patterns and best practices tools: Write, Edit, Read, Grep, Glob --- # Create TailwindCSS Component This command helps create well-structured, reusable components using TailwindCSS utilities following best practices and design system patterns. ## What This Command Does 1. **Component Architecture** - Creates component files with proper TailwindCSS utility composition - Implements responsive design patterns - Sets up proper TypeScript/PropTypes definitions - Follows accessibility best practices 2. **Utility Composition** - Uses semantic utility class combinations - Implements proper state management (hover, focus, active) - Creates responsive variants using breakpoint prefixes - Follows mobile-first methodology 3. **Design System Integration** - Uses design tokens from TailwindCSS configuration - Implements consistent spacing and typography scales - Applies proper color palette and semantic colors - Follows component variant patterns 4. **Performance Optimization** - Uses efficient utility combinations - Optimizes for CSS purging - Implements proper class composition strategies - Avoids unnecessary custom CSS ## Component Templates ### Button Component ```jsx // components/Button.jsx import React from 'react' import { cva } from 'class-variance-authority' import { cn } from '@/lib/utils' const buttonVariants = cva( // Base styles "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", }, }, defaultVariants: { variant: "default", size: "default", }, } ) export interface ButtonProps extends React.ButtonHTMLAttributes { variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' size?: 'default' | 'sm' | 'lg' | 'icon' loading?: boolean leftIcon?: React.ReactNode rightIcon?: React.ReactNode } const Button = React.forwardRef( ({ className, variant, size, loading, leftIcon, rightIcon, children, ...props }, ref) => { return ( ) } ) Button.displayName = "Button" export { Button, buttonVariants } ``` ### Card Component ```jsx // components/Card.jsx import React from 'react' import { cn } from '@/lib/utils' const Card = React.forwardRef< HTMLDivElement, React.HTMLAttributes & { hover?: boolean padding?: 'none' | 'sm' | 'md' | 'lg' } >(({ className, hover = false, padding = 'md', children, ...props }, ref) => { const paddingMap = { none: '', sm: 'p-4', md: 'p-6', lg: 'p-8' } return (
{children}
) }) const CardHeader = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)) const CardTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (

)) const CardDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (

)) const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (

)) const CardFooter = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)) Card.displayName = "Card" CardHeader.displayName = "CardHeader" CardTitle.displayName = "CardTitle" CardDescription.displayName = "CardDescription" CardContent.displayName = "CardContent" CardFooter.displayName = "CardFooter" export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } ``` ### Input Component ```jsx // components/Input.jsx import React from 'react' import { cva } from 'class-variance-authority' import { cn } from '@/lib/utils' const inputVariants = cva( "flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", { variants: { size: { sm: "h-8 px-2 text-xs", default: "h-10 px-3", lg: "h-12 px-4 text-base", }, state: { default: "", error: "border-destructive focus-visible:ring-destructive", success: "border-green-500 focus-visible:ring-green-500", }, }, defaultVariants: { size: "default", state: "default", }, } ) export interface InputProps extends React.InputHTMLAttributes { size?: 'sm' | 'default' | 'lg' state?: 'default' | 'error' | 'success' label?: string helperText?: string error?: string leftIcon?: React.ReactNode rightIcon?: React.ReactNode } const Input = React.forwardRef( ({ className, type, size, state, label, helperText, error, leftIcon, rightIcon, ...props }, ref) => { const inputState = error ? 'error' : state return (
{label && ( )}
{leftIcon && (
{leftIcon}
)} {rightIcon && (
{rightIcon}
)}
{(helperText || error) && (

{error || helperText}

)}
) } ) Input.displayName = "Input" export { Input, inputVariants } ``` ### Badge Component ```jsx // components/Badge.jsx import React from 'react' import { cva } from 'class-variance-authority' import { cn } from '@/lib/utils' const badgeVariants = cva( "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", { variants: { variant: { default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", success: "border-transparent bg-green-500 text-white hover:bg-green-600", warning: "border-transparent bg-yellow-500 text-white hover:bg-yellow-600", outline: "text-foreground", }, size: { sm: "px-2 py-0.5 text-xs", default: "px-2.5 py-0.5 text-xs", lg: "px-3 py-1 text-sm", }, }, defaultVariants: { variant: "default", size: "default", }, } ) export interface BadgeProps extends React.HTMLAttributes { variant?: 'default' | 'secondary' | 'destructive' | 'success' | 'warning' | 'outline' size?: 'sm' | 'default' | 'lg' removable?: boolean onRemove?: () => void } const Badge = React.forwardRef( ({ className, variant, size, removable, onRemove, children, ...props }, ref) => { return (
{children} {removable && ( )}
) } ) Badge.displayName = "Badge" export { Badge, badgeVariants } ``` ### Alert Component ```jsx // components/Alert.jsx import React from 'react' import { cva } from 'class-variance-authority' import { cn } from '@/lib/utils' const alertVariants = cva( "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", { variants: { variant: { default: "bg-background text-foreground", destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", success: "border-green-500/50 text-green-700 dark:text-green-400 [&>svg]:text-green-600", warning: "border-yellow-500/50 text-yellow-700 dark:text-yellow-400 [&>svg]:text-yellow-600", info: "border-blue-500/50 text-blue-700 dark:text-blue-400 [&>svg]:text-blue-600", }, }, defaultVariants: { variant: "default", }, } ) const Alert = React.forwardRef< HTMLDivElement, React.HTMLAttributes & { variant?: 'default' | 'destructive' | 'success' | 'warning' | 'info' dismissible?: boolean onDismiss?: () => void } >(({ className, variant, dismissible, onDismiss, children, ...props }, ref) => (
{children} {dismissible && ( )}
)) const AlertTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)) const AlertDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)) Alert.displayName = "Alert" AlertTitle.displayName = "AlertTitle" AlertDescription.displayName = "AlertDescription" export { Alert, AlertTitle, AlertDescription } ``` ## Layout Components ### Container Component ```jsx // components/Container.jsx import React from 'react' import { cn } from '@/lib/utils' export interface ContainerProps extends React.HTMLAttributes { size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' padding?: boolean } const Container = React.forwardRef( ({ className, size = 'lg', padding = true, ...props }, ref) => { const sizeClasses = { sm: 'max-w-2xl', md: 'max-w-4xl', lg: 'max-w-6xl', xl: 'max-w-7xl', '2xl': 'max-w-8xl', full: 'max-w-full' } return (
) } ) Container.displayName = 'Container' export { Container } ``` ### Grid Component ```jsx // components/Grid.jsx import React from 'react' import { cn } from '@/lib/utils' export interface GridProps extends React.HTMLAttributes { cols?: 1 | 2 | 3 | 4 | 5 | 6 | 12 gap?: 'none' | 'sm' | 'md' | 'lg' | 'xl' responsive?: boolean } const Grid = React.forwardRef( ({ className, cols = 1, gap = 'md', responsive = true, ...props }, ref) => { const gapClasses = { none: 'gap-0', sm: 'gap-2', md: 'gap-4', lg: 'gap-6', xl: 'gap-8' } const getResponsiveCols = (cols: number) => { if (!responsive) return `grid-cols-${cols}` switch (cols) { case 1: return 'grid-cols-1' case 2: return 'grid-cols-1 md:grid-cols-2' case 3: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3' case 4: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4' case 5: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5' case 6: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6' case 12: return 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-12' default: return `grid-cols-${cols}` } } return (
) } ) Grid.displayName = 'Grid' export { Grid } ``` ## Utility Functions ### Class Name Utility ```typescript // lib/utils.ts import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } // Responsive utility export function responsive( base: string, sm?: string, md?: string, lg?: string, xl?: string, xxl?: string ) { return cn( base, sm && `sm:${sm}`, md && `md:${md}`, lg && `lg:${lg}`, xl && `xl:${xl}`, xxl && `2xl:${xxl}` ) } // Focus ring utility export function focusRing(color: string = 'ring-primary') { return `focus:outline-none focus:ring-2 ${color} focus:ring-offset-2` } ``` ## Component Generation Script ### Auto-generate Component ```javascript // scripts/create-component.js const fs = require('fs') const path = require('path') function createComponent(name, type = 'basic') { const componentName = name.charAt(0).toUpperCase() + name.slice(1) const fileName = `${componentName}.tsx` const componentDir = `./components/${componentName}` // Create component directory if (!fs.existsSync(componentDir)) { fs.mkdirSync(componentDir, { recursive: true }) } const templates = { basic: basicComponentTemplate, form: formComponentTemplate, layout: layoutComponentTemplate, interactive: interactiveComponentTemplate } const template = templates[type] || templates.basic const componentCode = template(componentName, name) // Write component file fs.writeFileSync(path.join(componentDir, fileName), componentCode) // Create index file const indexContent = `export { ${componentName} } from './${componentName}'\nexport type { ${componentName}Props } from './${componentName}'` fs.writeFileSync(path.join(componentDir, 'index.ts'), indexContent) console.log(`✅ Component ${componentName} created successfully!`) console.log(`📁 Location: ${componentDir}`) console.log(`📝 Files created:`) console.log(` - ${fileName}`) console.log(` - index.ts`) } function basicComponentTemplate(componentName, kebabName) { return `import React from 'react' import { cn } from '@/lib/utils' export interface ${componentName}Props extends React.HTMLAttributes { variant?: 'default' | 'secondary' size?: 'sm' | 'md' | 'lg' } const ${componentName} = React.forwardRef( ({ className, variant = 'default', size = 'md', children, ...props }, ref) => { const variants = { default: 'bg-background text-foreground', secondary: 'bg-secondary text-secondary-foreground' } const sizes = { sm: 'p-2 text-sm', md: 'p-4 text-base', lg: 'p-6 text-lg' } return (
{children}
) } ) ${componentName}.displayName = '${componentName}' export { ${componentName} } ` } // Usage: node scripts/create-component.js MyComponent basic const [,, name, type] = process.argv if (!name) { console.error('Please provide a component name') process.exit(1) } createComponent(name, type) ``` Remember: **Focus on utility composition, responsive design, accessibility, and performance optimization when creating TailwindCSS components!**