---
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
// Grid layouts
// Container
Content
// Centering
```
### 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
Hover me
// 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 (
)
}
```
### Card
```typescript
// components/ui/card.tsx
export function Card({ children, className }: { children: React.ReactNode; className?: string }) {
return (
{children}
)
}
export function CardHeader({ children }: { children: React.ReactNode }) {
return {children}
}
export function CardTitle({ children }: { children: React.ReactNode }) {
return {children}
}
export function CardContent({ children }: { children: React.ReactNode }) {
return {children}
}
```
### Input
```typescript
// components/ui/input.tsx
export function Input({ className, ...props }: React.InputHTMLAttributes) {
return (
)
}
```
### Modal/Dialog
```typescript
'use client'
import { useEffect } from 'react'
import { X } from 'lucide-react'
interface DialogProps {
open: boolean
onClose: () => void
title?: string
children: React.ReactNode
}
export function Dialog({ open, onClose, title, children }: DialogProps) {
useEffect(() => {
if (open) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = 'unset'
}
return () => {
document.body.style.overflow = 'unset'
}
}, [open])
if (!open) return null
return (
{/* Backdrop */}
{/* Dialog */}
{title && (
{title}
)}
{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 && (
)}
)
}
export function DropdownMenuItem({ children, onClick }: {
children: React.ReactNode
onClick?: () => void
}) {
return (
{children}
)
}
```
### 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 (
)
}
```
## Animations
### Tailwind Transitions
```typescript
// Hover effects
Hover to scale
// Opacity fade
Fade in
// Transform
Slide on hover
```
### Framer Motion
```typescript
'use client'
import { motion } from 'framer-motion'
// Fade in
Fades in
// Slide in
Slides in
// Stagger children
{items.map(item => (
{item.title}
))}
```
## Icons
### Lucide React
```typescript
import { Search, User, Settings, ChevronRight } from 'lucide-react'
// Basic usage
// With color
// In button
Settings
```
## Loading States
### Skeleton
```typescript
export function Skeleton({ className }: { className?: string }) {
return (
)
}
// Usage
```
### Spinner
```typescript
export function Spinner({ className }: { className?: string }) {
return (
)
}
```
## Dark Mode
### Setup
```typescript
// app/providers.tsx
'use client'
import { ThemeProvider } from 'next-themes'
export function Providers({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
)
}
```
### Theme Toggle
```typescript
'use client'
import { useTheme } from 'next-themes'
import { Moon, Sun } from 'lucide-react'
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
setTheme(theme === 'dark' ? 'light' : 'dark')}
className="rounded-md p-2 hover:bg-gray-100 dark:hover:bg-gray-800"
>
)
}
```
### Dark Mode Styles
```typescript
// Tailwind dark mode
Dark mode aware
// tailwind.config.js
module.exports = {
darkMode: 'class',
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
}
}
}
}
```
## Best Practices
### Accessibility Checklist
- [ ] Use semantic HTML (header, nav, main, footer, article, section)
- [ ] Add alt text to images
- [ ] Ensure sufficient color contrast (4.5:1 for normal text)
- [ ] Support keyboard navigation (tab, enter, escape)
- [ ] Add ARIA labels where needed
- [ ] Use focus-visible for keyboard focus
- [ ] Test with screen reader
### Performance Checklist
- [ ] Use next/image for images
- [ ] Lazy load components not in viewport
- [ ] Minimize client-side JavaScript
- [ ] Use CSS animations over JS
- [ ] Implement loading skeletons
- [ ] Optimize font loading
- [ ] Use proper image formats (WebP, AVIF)
### Responsive Design Checklist
- [ ] Design mobile-first
- [ ] Test on multiple screen sizes
- [ ] Use responsive images
- [ ] Implement touch-friendly tap targets (44x44px minimum)
- [ ] Test landscape and portrait
- [ ] Handle safe areas on mobile
- [ ] Consider foldable devices
## Utility Function
```typescript
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
```
## Common Layouts
### Dashboard Layout
```typescript
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
{/* Sidebar */}
{/* Main content */}
{children}
)
}
```
### Landing Page Hero
```typescript
export function Hero() {
return (
Your Amazing Product
A compelling description that explains what your product does
Get Started
Learn More
)
}
```
## When to Use This Skill
Invoke this skill when:
- Building new UI components
- Creating layouts and page structures
- Implementing responsive design
- Adding animations and transitions
- Working with forms and inputs
- Implementing dark mode
- Ensuring accessibility
- Optimizing UI performance
- Creating loading states
- Building navigation components