--- name: ui-builder description: Expert guide for building beautiful, responsive UI with React, Tailwind CSS, Shadcn/ui, and modern design patterns. Use when creating components, layouts, animations, or styling. --- # UI/UX Builder Skill ## Overview This skill helps you build beautiful, accessible, and responsive user interfaces using modern React patterns, Tailwind CSS, and component libraries like Shadcn/ui. ## Core Principles ### 1. Mobile-First Design - Start with mobile layout - Use responsive breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px) - Test on multiple screen sizes ### 2. Accessibility - Use semantic HTML - Add ARIA labels where needed - Ensure keyboard navigation works - Maintain color contrast ratios - Support screen readers ### 3. Performance - Lazy load heavy components - Optimize images - Use CSS animations over JS when possible - Minimize re-renders ### 4. Consistency - Use design tokens (colors, spacing, typography) - Follow established patterns - Maintain visual hierarchy ## Tailwind CSS Patterns ### Layout ```typescript // Flex layouts
Left
Right
// Grid layouts
Card 1
Card 2
Card 3
// Container
Content
// Centering
Centered
``` ### Responsive Design ```typescript // Mobile first
Responsive text
// Hide/show by breakpoint
Desktop only
Mobile only
// Responsive padding/margin
Responsive padding
``` ### Colors & Themes ```typescript // Background colors
Content
// Text colors

Text

// Hover states // Focus states ``` ### Spacing ```typescript // Margin/Padding scale: 0, 1(4px), 2(8px), 4(16px), 6(24px), 8(32px), 12(48px), 16(64px)
Padding 16px
Margin top 32px, bottom 16px
Vertical spacing between children
Gap between flex/grid items
``` ## Common Component Patterns ### Button ```typescript // components/ui/button.tsx import { cn } from '@/lib/utils' interface ButtonProps extends React.ButtonHTMLAttributes { variant?: 'default' | 'outline' | 'ghost' | 'destructive' size?: 'sm' | 'md' | 'lg' } export function Button({ className, variant = 'default', size = 'md', ...props }: ButtonProps) { return ( )} {children} ) } ``` ### Dropdown Menu ```typescript 'use client' import { useState, useRef, useEffect } from 'react' export function DropdownMenu({ trigger, children }: { trigger: React.ReactNode children: React.ReactNode }) { const [open, setOpen] = useState(false) const ref = useRef(null) useEffect(() => { function handleClickOutside(event: MouseEvent) { if (ref.current && !ref.current.contains(event.target as Node)) { setOpen(false) } } document.addEventListener('mousedown', handleClickOutside) return () => document.removeEventListener('mousedown', handleClickOutside) }, []) return (
setOpen(!open)}>{trigger}
{open && (
{children}
)}
) } export function DropdownMenuItem({ children, onClick }: { children: React.ReactNode onClick?: () => void }) { return ( ) } ``` ### Form ```typescript // components/forms/contact-form.tsx 'use client' import { useState } from 'react' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' export function ContactForm() { const [loading, setLoading] = useState(false) const [errors, setErrors] = useState>({}) async function handleSubmit(e: React.FormEvent) { e.preventDefault() setLoading(true) setErrors({}) const formData = new FormData(e.currentTarget) const email = formData.get('email') as string const message = formData.get('message') as string // Validation const newErrors: Record = {} if (!email) newErrors.email = 'Email is required' if (!message) newErrors.message = 'Message is required' if (Object.keys(newErrors).length > 0) { setErrors(newErrors) setLoading(false) return } try { const response = await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, message }), }) if (!response.ok) throw new Error('Failed to send') // Success e.currentTarget.reset() alert('Message sent!') } catch (error) { setErrors({ submit: 'Failed to send message' }) } finally { setLoading(false) } } return (
{errors.email && (

{errors.email}

)}