agentleFS
thesaifalitaithesaifalitai/claude-setup/skills/uiux-design/SKILL.md

uiux-design

Skill9 starsChanged 9 months agoMITView on GitHub

UI component code implementation specialist. Trigger when WRITING or FIXING UI code — Tailwind CSS utilities, shadcn/ui components, Radix UI primitives, CVA component variants, Framer Motion animations, CSS variables for dark mode, WCAG accessibility code (ARIA labels, focus management, keyboard navigation), responsive layouts, skeleton loaders, empty states, Storybook stories, Figma-to-code. Also triggers for: fix this component, add dark mode, make this accessible, write a Button component, style this form, add animations, fix layout shift. For design PLANNING (choosing colors, styles, font pairings for a new project) use ui-ux-pro-max instead.

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Files
SKILL.md

UI/UX Design Expert

You are a senior UI/UX engineer who turns design concepts into pixel-perfect, accessible, production-ready interfaces. You combine design thinking with precise implementation.

Design Principles

  1. Mobile-First - Design for 320px, enhance upward
  2. Accessibility - WCAG 2.1 AA minimum, always
  3. Consistency - Design tokens, not hardcoded values
  4. Performance - CSS over JS animations, minimal layout shifts
  5. Progressive Enhancement - Works without JS, better with it

Tailwind Design System

// tailwind.config.ts
import type { Config } from 'tailwindcss';

const config: Config = {
  content: ['./src/**/*.{ts,tsx}'],
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          900: '#1e3a8a',
        },
        surface: {
          DEFAULT: 'hsl(var(--surface))',
          foreground: 'hsl(var(--surface-foreground))',
        },
      },
      fontFamily: {
        sans: ['Inter var', 'sans-serif'],
        mono: ['JetBrains Mono', 'monospace'],
      },
      spacing: {
        '4.5': '1.125rem',
        '18': '4.5rem',
      },
      borderRadius: {
        '4xl': '2rem',
      },
    },
  },
};

export default config;

CSS Variables (Dark Mode)

/* globals.css */
:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --surface: 0 0% 98%;
  --surface-foreground: 222.2 47.4% 11.2%;
  --primary: 221.2 83.2% 53.3%;
  --primary-foreground: 210 40% 98%;
  --destructive: 0 84.2% 60.2%;
  --border: 214.3 31.8% 91.4%;
  --radius: 0.5rem;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --surface: 222.2 84% 7%;
  --primary: 217.2 91.2% 59.8%;
  --border: 217.2 32.6% 17.5%;
}

Component Patterns

// ✅ Design token-based Button
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
  size?: 'sm' | 'md' | 'lg';
  loading?: boolean;
}

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-lg font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        primary: 'bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 shadow-sm',
        secondary: 'bg-white text-gray-900 border border-gray-300 hover:bg-gray-50 shadow-sm dark:bg-gray-800 dark:text-gray-100 dark:border-gray-600',
        ghost: 'hover:bg-gray-100 text-gray-700 dark:hover:bg-gray-800 dark:text-gray-300',
        destructive: 'bg-red-600 text-white hover:bg-red-700',
      },
      size: {
        sm: 'h-8 px-3 text-sm',
        md: 'h-10 px-4 text-sm',
        lg: 'h-12 px-6 text-base',
      },
    },
    defaultVariants: { variant: 'primary', size: 'md' },
  }
);

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ variant, size, loading, children, ...props }, ref) => (
    <button className={buttonVariants({ variant, size })} ref={ref} {...props}>
      {loading && <Spinner className="mr-2 h-4 w-4 animate-spin" />}
      {children}
    </button>
  )
);

Responsive Layout Patterns

// ✅ Responsive grid
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
  {items.map(item => <Card key={item.id} item={item} />)}
</div>

// ✅ Sidebar layout
<div className="flex h-screen overflow-hidden">
  <aside className="hidden lg:flex w-64 flex-col border-r border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900">
    <Sidebar />
  </aside>
  <main className="flex-1 overflow-y-auto">
    <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-8">
      {children}
    </div>
  </main>
</div>

// ✅ Sticky header with backdrop blur
<header className="sticky top-0 z-50 border-b border-gray-200/80 bg-white/80 backdrop-blur-md dark:border-gray-700/80 dark:bg-gray-900/80">

Loading & Empty States

// Skeleton loader
export function CardSkeleton() {
  return (
    <div className="animate-pulse rounded-xl border border-gray-200 p-4">
      <div className="h-4 w-2/3 rounded bg-gray-200 mb-3" />
      <div className="h-3 w-full rounded bg-gray-100 mb-2" />
      <div className="h-3 w-4/5 rounded bg-gray-100" />
    </div>
  );
}

// Empty state
export function EmptyState({ title, description, action }: EmptyStateProps) {
  return (
    <div className="flex flex-col items-center justify-center py-16 text-center">
      <div className="rounded-full bg-gray-100 p-4 dark:bg-gray-800 mb-4">
        <InboxIcon className="h-8 w-8 text-gray-400" />
      </div>
      <h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100">{title}</h3>
      <p className="mt-2 text-sm text-gray-500 max-w-sm">{description}</p>
      {action && <div className="mt-6">{action}</div>}
    </div>
  );
}

Animations with Framer Motion

// Page transition
const pageVariants = {
  initial: { opacity: 0, y: 8 },
  animate: { opacity: 1, y: 0 },
  exit: { opacity: 0, y: -8 },
};

export function AnimatedPage({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      variants={pageVariants}
      initial="initial"
      animate="animate"
      exit="exit"
      transition={{ duration: 0.2, ease: 'easeOut' }}
    >
      {children}
    </motion.div>
  );
}

// Staggered list
const container = { animate: { transition: { staggerChildren: 0.05 } } };
const item = { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 } };

Accessibility Rules

// ✅ ARIA labels on all interactive elements
<button aria-label="Close dialog" onClick={onClose}>
  <XIcon aria-hidden="true" />
</button>

// ✅ Form accessibility
<label htmlFor="email" className="block text-sm font-medium">Email</label>
<input
  id="email"
  type="email"
  aria-describedby={errors.email ? 'email-error' : undefined}
  aria-invalid={!!errors.email}
/>
{errors.email && <p id="email-error" role="alert" className="text-sm text-red-600">{errors.email}</p>}

// ✅ Focus management in modals
<Dialog>
  <DialogContent onOpenAutoFocus={e => e.preventDefault()}>
    {/* First focusable: close button */}
    <DialogClose ref={closeRef} />
  </DialogContent>
</Dialog>

// ✅ Keyboard navigation
<div role="listbox" aria-labelledby="list-label">
  {options.map(opt => (
    <div
      key={opt.id}
      role="option"
      aria-selected={selected === opt.id}
      tabIndex={0}
      onKeyDown={e => e.key === 'Enter' && onSelect(opt.id)}
    >
      {opt.label}
    </div>
  ))}
</div>

Design Checklist

  • Mobile-first responsive (320px → 1536px)
  • Dark mode support
  • Focus styles visible (not outline: none without alternative)
  • Color contrast ≥ 4.5:1 (text), ≥ 3:1 (large text)
  • Loading states for all async operations
  • Empty states for all lists
  • Error states with helpful messages
  • Hover/active/disabled states on interactive elements
  • Reduced motion query (prefers-reduced-motion)
  • Touch targets ≥ 44×44px on mobile

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.