From claude-skills
Provides opinionated constraints for building UI components, implementing animations, designing layouts, and reviewing frontend accessibility with Tailwind CSS, motion/react, and accessible primitives like Radix/Base UI.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claude-skills:ui-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Opinionated constraints for building better interfaces with agents.
Opinionated constraints for building better interfaces with agents.
| Requirement | Rule |
|---|---|
| Tailwind CSS | MUST use defaults (spacing, radius, shadows) before custom values |
| Animation library | MUST use motion/react (formerly framer-motion) for JS animation |
| CSS animation | SHOULD use tw-animate-css for entrance and micro-animations |
| Class logic | MUST use cn utility (clsx + tailwind-merge) |
| Requirement | Rule |
|---|---|
| Interactive primitives | MUST use accessible primitives (Base UI, React Aria, Radix) for keyboard/focus behavior |
| Existing components | MUST use project's existing primitives first |
| Consistency | NEVER mix primitive systems within the same interaction surface |
| New primitives | SHOULD prefer Base UI if compatible with stack |
| Icon buttons | MUST add aria-label to icon-only buttons |
| Custom behavior | NEVER rebuild keyboard or focus behavior by hand unless explicitly requested |
| Requirement | Rule |
|---|---|
| Destructive actions | MUST use AlertDialog for destructive or irreversible actions |
| Loading states | SHOULD use structural skeletons |
| Viewport height | NEVER use h-screen, use h-dvh |
| Fixed elements | MUST respect safe-area-inset |
| Error display | MUST show errors next to where the action happens |
| Input behavior | NEVER block paste in input or textarea elements |
| Requirement | Rule |
|---|---|
| Default | NEVER add animation unless explicitly requested |
| Compositor props | MUST animate only transform, opacity |
| Layout props | NEVER animate width, height, top, left, margin, padding |
| Paint props | SHOULD avoid background, color except for small, local UI (text, icons) |
| Entrance easing | SHOULD use ease-out on entrance |
| Feedback timing | NEVER exceed 200ms for interaction feedback |
| Looping | MUST pause looping animations when off-screen |
| Accessibility | MUST respect prefers-reduced-motion |
| Custom easing | NEVER introduce custom easing curves unless explicitly requested |
| Large surfaces | SHOULD avoid animating large images or full-screen surfaces |
| Requirement | Rule |
|---|---|
| Headings | MUST use text-balance |
| Body text | MUST use text-pretty for paragraphs |
| Data | MUST use tabular-nums |
| Dense UI | SHOULD use truncate or line-clamp |
| Letter spacing | NEVER modify letter-spacing (tracking-) unless explicitly requested |
| Requirement | Rule |
|---|---|
| Z-index | MUST use a fixed scale (no arbitrary z-x) |
| Square elements | SHOULD use size-x instead of w-x + h-x |
| Requirement | Rule |
|---|---|
| Blur effects | NEVER animate large blur() or backdrop-filter surfaces |
| Will-change | NEVER apply will-change outside an active animation |
| useEffect | NEVER use for anything expressible as render logic |
| Requirement | Rule |
|---|---|
| Gradients | NEVER use unless explicitly requested |
| Purple/multicolor gradients | NEVER use |
| Glow effects | NEVER use as primary affordances |
| Shadows | SHOULD use Tailwind CSS default scale unless explicitly requested |
| Empty states | MUST give one clear next action |
| Accent colors | SHOULD limit to one per view |
| Color tokens | SHOULD use existing theme or Tailwind CSS tokens before introducing new ones |
The most common UI design failures occur in spacing, color contrast, mobile responsiveness, state management, and visual hierarchy. These gotchas are discovered through repeated agent mistakes when building interfaces.
Problem: Using an inconsistent mix of Tailwind spacing values without a deliberate system makes layouts feel incoherent.
// ❌ WRONG - arbitrary pixel values, no spacing system
<div className="ml-[13px] mr-[22px] pt-[7px]">Content</div>
// ✅ CORRECT - use system scales
<div className="ml-4 mr-4 pt-4">Content</div>
Why it fails:
2px, some is 16px, no pattern)Fix:
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, etc.)px-4 py-2p-6gap-8ml-6 (not ml-3)gap-x for all horizontal lists)Problem: Color combinations that fail WCAG AA contrast ratios (4.5:1 for text, 3:1 for UI components) making content illegible for low-vision users.
// ❌ WRONG - gray-400 text on gray-100 background fails contrast
<p className="text-gray-400 bg-gray-100">Important content</p>
// ✅ CORRECT - gray-700 on gray-100 passes WCAG AA
<p className="text-gray-700 bg-gray-100">Important content</p>
Why it fails:
Fix:
text-gray-900/text-white on any background (always safe)text-gray-700 on light backgroundstext-gray-300 on dark backgroundsgray-400 on gray-100 ❌red-500 on pink-100 ❌text-gray-400 on white, text-gray-600 on colorred-700 not red-300)Problem: Touch targets smaller than 44×44px, horizontal scrolling, or layouts that don't adapt to narrow viewports.
// ❌ WRONG - button too small, no responsive layout
<button className="px-2 py-1 text-xs">Click me</button>
<div className="flex gap-2">
<div className="w-80">Sidebar</div>
<div className="w-80">Content</div>
</div>
// ✅ CORRECT - hit target size, responsive stack
<button className="px-4 py-3 md:px-6 md:py-3">Click me</button>
<div className="flex flex-col md:flex-row gap-4">
<div className="w-full md:w-80">Sidebar</div>
<div className="flex-1">Content</div>
</div>
Why it fails:
Fix:
px-4 py-3 (standard: px-6 py-3)flex-col by default, md:flex-row for desktopw-full on mobile, md:w-80 or md:w-1/3 on desktopflex-1 instead of fixed widths for flexible layoutsProblem: Interfaces that only show the happy path, failing silently when loading, erroring, or empty.
// ❌ WRONG - no feedback states
<button onClick={save}>Save</button>
<div>{data.map(item => <ItemCard item={item} />)}</div>
// ✅ CORRECT - all states accounted for
<button onClick={save} disabled={loading}>
{loading ? 'Saving...' : 'Save'}
</button>
{loading && <LoadingSkeleton />}
{error && <ErrorAlert message={error} />}
{!loading && data.length === 0 && <EmptyState action="Create your first item" />}
{!loading && !error && data.map(item => <ItemCard item={item} />)}
Why it fails:
Fix:
disabled={true} + opacity-50 or cursor-not-allowedProblem: All text the same size, all colors the same weight, all spacing the same distance — nothing stands out.
// ❌ WRONG - flat hierarchy
<div className="text-lg text-gray-700">
<div className="text-lg text-gray-700">Subheading</div>
<div className="text-lg text-gray-700">Subtitle</div>
<button className="text-lg px-4 py-2">Action</button>
</div>
// ✅ CORRECT - clear hierarchy
<div>
<h1 className="text-3xl font-bold text-gray-900">Title</h1>
<h2 className="text-xl font-semibold text-gray-700 mt-6">Subheading</h2>
<p className="text-base text-gray-600 mt-2">Subtitle</p>
<button className="mt-6 px-6 py-3 bg-blue-600 text-white font-semibold rounded">
Primary Action
</button>
</div>
Why it fails:
Fix:
text-3xl (h1) → text-2xl (h2) → text-xl (h3)text-base (paragraphs) → text-sm (secondary)font-bold or font-semiboldfont-semiboldfont-normalfont-normal with lighter colortext-gray-900text-gray-600text-gray-500gap-8 (largest)gap-4gap-2transform, opacity
width, height, top, left, margin, padding, blur(), backdrop-filter
// Icon button - always add aria-label
<button aria-label="Close dialog">
<XIcon />
</button>
// Respect reduced motion
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; }
}
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
npx claudepluginhub ckorhonen/claude-skillsProvides UI/UX design guidance for unique, accessible web interfaces covering colors, typography, layouts. Always asks before decisions; activates for building web components, pages, apps.
Guides creation of intentional, production-grade frontend interfaces covering design thinking, interaction patterns, motion, forms, layout, accessibility, and performance.
Enforces WCAG 2.1 AA compliance for Tailwind CSS web UI: color contrast, focus states, dark mode contrast, and visible button boundaries.