
ui-web
PopularWeb UI - glassmorphism, Tailwind, dark mode, accessibility
Web UI - glassmorphism, Tailwind, dark mode, accessibility
UI Design Skill (Web)
Load with: base.md + react-web.md
MANDATORY: WCAG 2.1 AA Compliance
These rules are NON-NEGOTIABLE. Every UI element must pass these checks.
1. Color Contrast (CRITICAL)
Text Contrast Requirements:
├── Normal text (<18px): 4.5:1 minimum
├── Large text (≥18px bold or ≥24px): 3:1 minimum
├── UI components (buttons, inputs): 3:1 minimum
└── Focus indicators: 3:1 minimum
FORBIDDEN COLOR COMBINATIONS:
✗ gray-400 on white (#9CA3AF on #FFFFFF = 2.6:1) - FAILS
✗ gray-500 on white (#6B7280 on #FFFFFF = 4.6:1) - BARELY PASSES
✗ white on yellow - FAILS
✗ light blue on white - USUALLY FAILS
SAFE COLOR COMBINATIONS:
✓ gray-700 on white (#374151 on #FFFFFF = 9.2:1)
✓ gray-600 on white (#4B5563 on #FFFFFF = 6.4:1)
✓ gray-900 on white (#111827 on #FFFFFF = 16:1)
✓ white on gray-900, blue-600, green-700
2. Visibility Rules (CRITICAL)
ALL BUTTONS MUST HAVE:
✓ Visible background color OR visible border (min 1px)
✓ Text color that contrasts with background
✓ Minimum height: 44px (touch target)
✓ Padding: at least px-4 py-2
NEVER CREATE:
✗ Buttons with transparent background AND no border
✗ Text same color as background
✗ Ghost buttons without visible borders
✗ White text on light backgrounds
✗ Dark text on dark backgrounds
3. Required Element Styles
// EVERY button needs visible boundaries
// PRIMARY: solid background
<button className="bg-gray-900 text-white px-4 py-3 rounded-lg">
Primary
</button>
// SECONDARY: visible background
<button className="bg-gray-100 text-gray-900 px-4 py-3 rounded-lg">
Secondary
</button>
// GHOST: MUST have visible border
<button className="border border-gray-300 text-gray-700 px-4 py-3 rounded-lg">
Ghost
</button>
// NEVER DO THIS:
<button className="text-gray-500">Invisible Button</button> // ✗ NO BOUNDARY
<button className="bg-white text-white">Hidden</button> // ✗ NO CONTRAST
4. Focus States (REQUIRED)
// EVERY interactive element needs visible focus
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
// NEVER remove focus without replacement
className="outline-none" // ✗ FORBIDDEN without ring replacement
5. Dark Mode Contrast
When implementing dark mode:
├── Text must be light (gray-100 to white) on dark backgrounds
├── Borders must be visible (gray-700 or lighter)
├── Never use gray-400 text on gray-900 bg (fails contrast)
└── Test BOTH modes before shipping
SAFE DARK MODE TEXT:
✓ text-white on bg-gray-900
✓ text-gray-100 on bg-gray-800
✓ text-gray-200 on bg-gray-900
UNSAFE (FAILS CONTRAST):
✗ text-gray-500 on bg-gray-900 (2.4:1)
✗ text-gray-400 on bg-gray-800 (3.1:1)
Core Philosophy
Beautiful UI is not decoration - it's communication. Every visual choice should serve clarity, hierarchy, and user confidence. Default to elegance and restraint.
Design Principles
1. Visual Hierarchy
Primary Action → Bold, high contrast, prominent
Secondary Action → Subtle, lower contrast
Tertiary/Links → Minimal, text-style
2. Spacing System (8px Grid)
// Tailwind spacing scale - USE CONSISTENTLY
const spacing = {
xs: 'p-1', // 4px - tight internal
sm: 'p-2', // 8px - compact
md: 'p-4', // 16px - default
lg: 'p-6', // 24px - comfortable
xl: 'p-8', // 32px - spacious
'2xl': 'p-12', // 48px - section gaps
};
// Rule: More whitespace = more premium feel
// Rule: Consistent spacing > perfect spacing
3. Typography Scale
// Limit to 3-4 font sizes per page
const typography = {
hero: 'text-4xl md:text-5xl font-bold tracking-tight',
heading: 'text-2xl md:text-3xl font-semibold',
subheading: 'text-lg md:text-xl font-medium',
body: 'text-base leading-relaxed',
caption: 'text-sm text-gray-500',
};
// Rule: Never use more than 2 font families
// Rule: Line height 1.5-1.7 for body text
Glassmorphism (Web)
Base Glass Card
// Modern glass effect - use sparingly for emphasis
const GlassCard = ({ children, className = '' }) => (
<div className={`
backdrop-blur-xl
bg-white/10
border border-white/20
rounded-2xl
shadow-xl
shadow-black/5
${className}
`}>
{children}
</div>
);
Glass Variants
// Light mode glass
const lightGlass = `
backdrop-blur-xl
bg-white/70
border border-white/50
shadow-lg shadow-gray-200/50
`;
// Dark mode glass
const darkGlass = `
backdrop-blur-xl
bg-gray-900/70
border border-white/10
shadow-xl shadow-black/20
`;
// Frosted sidebar
const frostedSidebar = `
backdrop-blur-2xl
bg-gradient-to-b from-white/80 to-white/60
border-r border-white/30
`;
// Floating action glass
const floatingGlass = `
backdrop-blur-md
bg-white/90
rounded-full
shadow-lg shadow-black/10
border border-white/50
`;
When to Use Glassmorphism
✓ Hero sections with image backgrounds
✓ Floating cards over gradients
✓ Modal overlays
✓ Navigation bars (subtle)
✓ Feature highlights
✗ Every card (overuse kills the effect)
✗ Text-heavy content areas
✗ Forms (reduces contrast)
✗ Data tables
Color System
Semantic Colors
const colors = {
// Actions
primary: 'bg-blue-600 hover:bg-blue-700',
secondary: 'bg-gray-100 hover:bg-gray-200 text-gray-900',
danger: 'bg-red-600 hover:bg-red-700',
success: 'bg-green-600 hover:bg-green-700',
// Surfaces
background: 'bg-gray-50 dark:bg-gray-950',
surface: 'bg-white dark:bg-gray-900',
elevated: 'bg-white dark:bg-gray-800 shadow-lg',
// Text
textPrimary: 'text-gray-900 dark:text-white',
textSecondary: 'text-gray-600 dark:text-gray-400',
textMuted: 'text-gray-400 dark:text-gray-500',
};
Gradient Backgrounds
// Subtle mesh gradient (modern, premium)
const meshGradient = `
bg-gradient-to-br
from-blue-50 via-white to-purple-50
dark:from-gray-950 dark:via-gray-900 dark:to-gray-950
`;
// Vibrant hero gradient
const heroGradient = `
bg-gradient-to-r
from-blue-600 via-purple-600 to-pink-600
`;
// Subtle radial glow
const radialGlow = `
bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))]
from-blue-200/40 via-transparent to-transparent
`;
Component Patterns
Buttons
// Primary button - bold, confident
const PrimaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-900 dark:bg-white
text-white dark:text-gray-900
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-800 dark:hover:bg-gray-100
hover:shadow-lg hover:shadow-gray-900/20
active:scale-[0.98]
disabled:opacity-50 disabled:cursor-not-allowed
"
{...props}
>
{children}
</button>
);
// Secondary button - subtle
const SecondaryButton = ({ children, ...props }) => (
<button
className="
px-6 py-3
bg-gray-100 dark:bg-gray-800
text-gray-900 dark:text-white
font-medium
rounded-xl
transition-all duration-200
hover:bg-gray-200 dark:hover:bg-gray-700
active:scale-[0.98]
"
{...props}
>
{children}
</button>
);
// Ghost button - minimal
const GhostButton = ({ children, ...props }) => (
<button
className="
px-4 py-2
text-gray-600 dark:text-gray-400
font-medium
rounded-lg
transition-colors duration-200
hover:text-gray-900 dark:hover:text-white
hover:bg-gray-100 dark:hover:bg-gray-800
"
{...props}
>
{children}
</button>
);
Cards
// Clean card with subtle elevation
const Card = ({ children, className = '' }) => (
<div className={`
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
shadow-sm
hover:shadow-md
transition-shadow duration-300
${className}
`}>
{children}
</div>
);
// Interactive card
const InteractiveCard = ({ children, onClick }) => (
<button
onClick={onClick}
className="
w-full text-left
bg-white dark:bg-gray-900
rounded-2xl
border border-gray-200 dark:border-gray-800
p-6
transition-all duration-300
hover:border-gray-300 dark:hover:border-gray-700
hover:shadow-lg
hover:-translate-y-1
active:scale-[0.99]
"
>
{children}
</button>
);
Input Fields
const Input = ({ label, error, ...props }) => (
<div className="space-y-2">
{label && (
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
{label}
</label>
)}
<input
className={`
w-full px-4 py-3
bg-gray-50 dark:bg-gray-800
border-2 rounded-xl
text-gray-900 dark:text-white
placeholder-gray-400 dark:placeholder-gray-500
transition-all duration-200
focus:outline-none focus:ring-0
${error
? 'border-red-500 focus:border-red-500'
: 'border-transparent focus:border-blue-500 focus:bg-white dark:focus:bg-gray-900'
}
`}
{...props}
/>
{error && (
<p className="text-sm text-red-500">{error}</p>
)}
</div>
);
Micro-Interactions
Transitions
// Standard transitions - ALWAYS use
const transitions = {
fast: 'transition-all duration-150', // Hover states
normal: 'transition-all duration-200', // Most interactions
slow: 'transition-all duration-300', // Card hovers, modals
spring: 'transition-all duration-500 ease-out', // Page transitions
};
// Rule: Everything interactive should transition
// Rule: 150-300ms feels responsive, >500ms feels slow
Hover Effects
// Scale on hover (buttons, cards)
className="hover:scale-105 active:scale-95 transition-transform"
// Lift on hover (cards)
className="hover:-translate-y-1 hover:shadow-xl transition-all"
// Glow on hover (CTAs)
className="hover:shadow-lg hover:shadow-blue-500/25 transition-shadow"
// Border highlight (inputs, cards)
className="hover:border-gray-300 transition-colors"
Loading States
// Skeleton loader
const Skeleton = ({ className = '' }) => (
<div className={`
animate-pulse
bg-gray-200 dark:bg-gray-800
rounded-lg
${className}
`} />
);
// Spinner
const Spinner = ({ size = 'md' }) => (
<div className={`
animate-spin rounded-full
border-2 border-gray-200 dark:border-gray-700
border-t-blue-600
${size === 'sm' ? 'w-4 h-4' : size === 'lg' ? 'w-8 h-8' : 'w-6 h-6'}
`} />
);
// Button loading state
<button disabled className="relative">
<span className="opacity-0">Submit</span>
<Spinner className="absolute inset-0 m-auto" />
</button>
Layout Patterns
Container
// Consistent max-width and padding
const Container = ({ children, className = '' }) => (
<div className={`
max-w-7xl mx-auto
px-4 sm:px-6 lg:px-8
${className}
`}>
{children}
</div>
);
Section Spacing
// Consistent vertical rhythm
const Section = ({ children }) => (
<section className="py-16 md:py-24">
<Container>{children}</Container>
</section>
);
Grid Systems
// Feature grid
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{features.map(f => <FeatureCard key={f.id} {...f} />)}
</div>
// Bento grid (modern asymmetric)
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="col-span-2 row-span-2">Large</div>
<div className="col-span-1">Small</div>
<div className="col-span-1">Small</div>
<div className="col-span-2">Medium</div>
</div>
Dark Mode
Implementation
// Always design for both modes
// Use CSS variables or Tailwind dark: prefix
// Theme toggle
const ThemeToggle = () => {
const [dark, setDark] = useState(false);
useEffect(() => {
document.documentElement.classList.toggle('dark', dark);
}, [dark]);
return (
<button onClick={() => setDark(!dark)}>
{dark ? <SunIcon /> : <MoonIcon />}
</button>
);
};
Color Pairing
Light Mode Dark Mode
─────────────────────────────────
white gray-950
gray-50 gray-900
gray-100 gray-800
gray-200 gray-700
gray-900 (text) white (text)
gray-600 (secondary) gray-400
blue-600 blue-500
Accessibility
Contrast Requirements
WCAG AA: 4.5:1 for normal text, 3:1 for large text
WCAG AAA: 7:1 for normal text, 4.5:1 for large text
// Test: Use browser devtools or contrast checker
// Rule: Never use gray-400 on white for body text
Focus States
// Always visible focus rings
className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
"
// Never remove focus styles without replacement
// ✗ outline-none (alone)
// ✓ outline-none + focus-visible:ring
Screen Readers
// Visually hidden but accessible
const srOnly = "absolute w-px h-px p-0 -m-px overflow-hidden whitespace-nowrap border-0";
// Icon buttons need labels
<button aria-label="Close menu">
<XIcon className="w-6 h-6" />
</button>
// Announce dynamic content
<div role="status" aria-live="polite">
{message}
</div>
Anti-Patterns
Never Do
✗ More than 3 font sizes on a page
✗ Random spacing values (use 8px grid)
✗ Pure black (#000) on pure white (#fff)
✗ Colored text on colored backgrounds without checking contrast
✗ Animations longer than 500ms for UI elements
✗ Glassmorphism everywhere
✗ Drop shadows on everything
✗ Gradients on text (hard to read)
✗ Auto-playing animations that can't be stopped
✗ Removing focus indicators
✗ Gray text below 4.5:1 contrast
✗ Tiny click targets (< 44px)
Common Mistakes
// ✗ Too many shadows
className="shadow-sm shadow-md shadow-lg" // Pick ONE
// ✗ Inconsistent rounding
className="rounded-sm rounded-lg rounded-2xl" // System: sm, lg, xl, 2xl
// ✗ Competing focal points
// One primary CTA per viewport
// ✗ Over-decorated
// If it doesn't serve function, remove it
Quick Reference
Modern Defaults
// Border radius: 12-16px (rounded-xl to rounded-2xl)
// Shadow: subtle (shadow-sm to shadow-md)
// Font: Inter, SF Pro, system-ui
// Primary: Near-black or brand color
// Transitions: 200ms ease-out
// Spacing: 8px grid (Tailwind default)
Premium Feel Checklist
□ Generous whitespace
□ Subtle shadows (not harsh)
□ Smooth transitions on all interactions
□ Consistent border radius
□ Limited color palette (2-3 colors max)
□ Typography hierarchy (3 sizes max)
□ High-quality imagery
□ Micro-interactions on hover/focus
□ Dark mode support
You Might Also Like
Related Skills

cache-components
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.
vercel
component-refactoring
Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
langgenius
web-artifacts-builder
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
anthropics
frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
anthropics
react-modernization
Upgrade React applications to latest versions, migrate from class components to hooks, and adopt concurrent features. Use when modernizing React codebases, migrating to React Hooks, or upgrading to latest React versions.
wshobson
tailwind-design-system
Build scalable design systems with Tailwind CSS v4, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.
wshobson