Back to list
erikpr1994

frontend-design

by erikpr1994

0🍴 0📅 Jan 22, 2026

SKILL.md


name: frontend-design description: "Use when designing UI components, implementing accessibility, responsive layouts, or integrating with design systems."

Frontend Design

Overview

UI/UX implementation patterns covering component design, accessibility requirements, responsive design, and design system integration. Focus on building consistent, accessible, and maintainable interfaces.

When to Use

  • Designing new UI components
  • Implementing accessibility features
  • Creating responsive layouts
  • Integrating with design systems
  • Styling with CSS/Tailwind

Quick Reference

AspectKey Principles
ComponentsSingle responsibility, composable, typed props
AccessibilitySemantic HTML, ARIA, keyboard nav, focus
ResponsiveMobile-first, breakpoints, fluid sizing
Design SystemTokens, consistent spacing, reusable

Component Design Principles

Structure

// Good: Single responsibility, typed props
interface ButtonProps {
  variant: 'primary' | 'secondary' | 'ghost';
  size: 'sm' | 'md' | 'lg';
  isLoading?: boolean;
  disabled?: boolean;
  children: React.ReactNode;
  onClick?: () => void;
}

export function Button({
  variant,
  size,
  isLoading = false,
  disabled = false,
  children,
  onClick,
}: ButtonProps) {
  return (
    <button
      className={cn(
        buttonBase,
        variants[variant],
        sizes[size],
        isLoading && 'opacity-50 cursor-wait'
      )}
      disabled={disabled || isLoading}
      onClick={onClick}
    >
      {isLoading ? <Spinner /> : children}
    </button>
  );
}

Component Checklist

  • Props are typed with TypeScript
  • Default props for optional values
  • Composable (accepts children or slots)
  • Accessible (proper ARIA, keyboard)
  • Responsive (works on all screen sizes)
  • Tested (unit + visual)

Accessibility Requirements

WCAG 2.1 AA Essentials

RequirementImplementation
Color Contrast4.5:1 text, 3:1 large text/graphics
Focus VisibleClear focus ring on all interactive elements
Keyboard NavAll functions accessible via keyboard
Alt TextDescriptive alt for images
Form LabelsEvery input has associated label
Error MessagesClear, associated with field

Semantic HTML

<!-- Good: Semantic structure -->
<header>
  <nav aria-label="Main navigation">
    <ul role="list">
      <li><a href="/home">Home</a></li>
    </ul>
  </nav>
</header>

<main>
  <article>
    <h1>Page Title</h1>
    <section aria-labelledby="section-heading">
      <h2 id="section-heading">Section</h2>
    </section>
  </article>
</main>

<footer>...</footer>

ARIA Patterns

// Dialog/Modal
<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-description"
>
  <h2 id="dialog-title">Confirm Action</h2>
  <p id="dialog-description">Are you sure?</p>
</div>

// Tab Panel
<div role="tablist">
  <button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
  <button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
</div>
<div role="tabpanel" id="panel-1">Content 1</div>

// Live Region (announcements)
<div aria-live="polite" aria-atomic="true">
  {statusMessage}
</div>

Keyboard Navigation

// Focus trap for modals
useEffect(() => {
  const focusableElements = modalRef.current?.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusableElements?.[0];
  const last = focusableElements?.[focusableElements.length - 1];

  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === 'Tab') {
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last?.focus();
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first?.focus();
      }
    }
    if (e.key === 'Escape') onClose();
  };

  document.addEventListener('keydown', handleKeyDown);
  return () => document.removeEventListener('keydown', handleKeyDown);
}, []);

Responsive Design Patterns

Mobile-First Breakpoints

/* Tailwind default breakpoints */
/* sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px */

/* Mobile-first approach */
.container {
  padding: 1rem;        /* Mobile default */
}

@media (min-width: 768px) {
  .container {
    padding: 2rem;      /* Tablet+ */
  }
}

@media (min-width: 1024px) {
  .container {
    padding: 4rem;      /* Desktop */
  }
}

Tailwind Responsive

<div className={cn(
  // Mobile first
  "flex flex-col gap-4 p-4",
  // Tablet
  "md:flex-row md:gap-6 md:p-6",
  // Desktop
  "lg:gap-8 lg:p-8"
)}>

Common Patterns

// Responsive grid
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">

// Hide/show by breakpoint
<nav className="hidden md:flex">        {/* Desktop nav */}
<button className="md:hidden">          {/* Mobile menu button */}

// Responsive typography
<h1 className="text-2xl md:text-4xl lg:text-5xl">

// Responsive spacing
<section className="py-8 md:py-12 lg:py-16">

Design System Integration

Design Tokens

// tokens.ts
export const tokens = {
  colors: {
    primary: {
      50: '#eff6ff',
      500: '#3b82f6',
      900: '#1e3a8a',
    },
    semantic: {
      success: '#22c55e',
      warning: '#f59e0b',
      error: '#ef4444',
    },
  },
  spacing: {
    xs: '0.25rem',
    sm: '0.5rem',
    md: '1rem',
    lg: '1.5rem',
    xl: '2rem',
  },
  radius: {
    sm: '0.25rem',
    md: '0.5rem',
    lg: '1rem',
    full: '9999px',
  },
};

Tailwind Config

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: tokens.colors.primary,
        success: tokens.colors.semantic.success,
      },
      spacing: tokens.spacing,
      borderRadius: tokens.radius,
    },
  },
};

Consistent Component API

// All components follow same patterns
type Size = 'sm' | 'md' | 'lg';
type Variant = 'primary' | 'secondary' | 'ghost';

interface BaseProps {
  size?: Size;
  variant?: Variant;
  className?: string;
}

// Button, Input, Card, etc. all use BaseProps

Common Patterns

Loading States

// Skeleton loader
<div className="animate-pulse">
  <div className="h-4 bg-gray-200 rounded w-3/4 mb-2" />
  <div className="h-4 bg-gray-200 rounded w-1/2" />
</div>

// Spinner
<svg className="animate-spin h-5 w-5" viewBox="0 0 24 24">
  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>

Error States

<div role="alert" className="bg-red-50 border-l-4 border-red-500 p-4">
  <div className="flex">
    <AlertIcon className="text-red-500" />
    <div className="ml-3">
      <p className="text-red-700 font-medium">Error</p>
      <p className="text-red-600 text-sm">{errorMessage}</p>
    </div>
  </div>
</div>

Red Flags - STOP

Never:

  • Use div with click handlers (use button)
  • Remove focus outlines without replacement
  • Rely only on color to convey information
  • Skip alt text on meaningful images
  • Use fixed widths that break on mobile

Always:

  • Test with keyboard navigation
  • Check color contrast
  • Provide focus indicators
  • Use semantic HTML elements
  • Test on multiple screen sizes

Integration

Related skills: react-patterns, nextjs-patterns Tools: Lighthouse, axe DevTools, WAVE

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon