Communitygithub.com

프론트엔드 UI 엔지니어링

접근성, 성능, 시각적 완성도를 갖춘 프로덕션 품질의 사용자 인터페이스를 구축합니다. 인터페이스나 페이지를 만들거나 수정할 때, 컴포넌트를 생성할 때, 레이아웃을 구현할 때, WCAG 접근성 요구 사항을 충족할 때, 상태를 관리할 때, 또는 AI가 생성한 느낌이 아닌 프로덕션 품질의 결과물이 필요할 때 사용하세요.

프론트엔드 UI 엔지니어링란 무엇인가요?

이 스킬은 접근성, 성능, 시각적 완성도를 갖춘 프로덕션 품질의 사용자 인터페이스를 구축하는 데 특화되어 있습니다. 주요 목표는 디자인 감각을 갖춘 엔지니어가 만든 것처럼 보이게 하는 것이며, AI가 생성한 일반적인 'AI 미학'을 피하는 것입니다. 이 스킬은 컴포넌트 아키텍처, 상태 관리, 디자인 시스템 준수, WCAG 2.1 AA 접근성, 반응형 디자인, 로딩 및 전환 처리에 대한 구체적인 지침을 제공합니다. 또한, AI 생성 UI에서 흔히 발견되는 문제점(예: 보라색/인디고 색상, 과도한 그라데이션, 둥근 모서리, 그림자 과다 사용 등)을 피하고 프로젝트의 실제 디자인 시스템을 사용하도록 권장합니다. 이 스킬은 컴포넌트 분리 (데이터 가져오기와 표현 분리), 합성 지향적 패턴, 키보드 내비게이션, ARIA 레이블, 포커스 관리, 의미 있는 빈 상태 및 오류 상태 처리에 대한 모범 사례를 포함합니다. 또한, 재사용 가능한 패턴, 책임 분리, 유지보수성을 강조하는 구체적인 파일 구조 예제와 코드 스니펫을 제공합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/addyosmani/agent-skills/tree/HEAD/skills/frontend-ui-engineering

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

프론트엔드 UI 엔지니어링은(는) 무엇을 하나요?

개요

접근성, 성능, 시각적으로 완성된 프로덕션 품질의 사용자 인터페이스를 구축합니다. 목표는 최고의 회사에서 디자인을 아는 엔지니어가 구축한 것처럼 보이는 UI를 만드는 것입니다. AI가 생성한 것처럼 보이지 않아야 합니다. 이는 실제 디자인 시스템 준수, 적절한 접근성, 세심한 상호작용 패턴, 그리고 일반적인 'AI 미학'이 없음을 의미합니다.

사용 시기

  • 새 UI 컴포넌트 또는 페이지 구축
  • 기존 사용자 대면 인터페이스 수정
  • 반응형 레이아웃 구현
  • 상호작용 또는 상태 관리 추가
  • 시각적 또는 UX 문제 수정

컴포넌트 아키텍처

파일 구조

컴포넌트와 관련된 모든 파일을 한 곳에 모읍니다:

src/components/
  TaskList/
    TaskList.tsx          # 컴포넌트 구현
    TaskList.test.tsx     # 테스트
    TaskList.stories.tsx  # Storybook 스토리 (사용하는 경우)
    use-task-list.ts      # 사용자 정의 훅 (복잡한 상태인 경우)
    types.ts              # 컴포넌트 특정 타입 (필요한 경우)

컴포넌트 패턴

설정보다 합성을 선호하세요:

// 좋음: 합성 가능
<Card>
  <CardHeader>
    <CardTitle>작업</CardTitle>
  </CardHeader>
  <CardBody>
    <TaskList tasks={tasks} />
  </CardBody>
</Card>

// 피해야 할 것: 지나친 설정
<Card
  title="작업"
  headerVariant="large"
  bodyPadding="md"
  content={<TaskList tasks={tasks} />}
/>

컴포넌트를 집중적으로 유지하세요:

// 좋음: 한 가지 일만 함
export function TaskItem({ task, onToggle, onDelete }: TaskItemProps) {
  return (
    <li className="flex items-center gap-3 p-3">
      <Checkbox checked={task.done} onChange={() => onToggle(task.id)} />
      <span className={task.done ? 'line-through text-muted' : ''}>{task.title}</span>
      <Button variant="ghost" size="sm" onClick={() => onDelete(task.id)}>
        <TrashIcon />
      </Button>
    </li>
  );
}

데이터 가져오기와 프레젠테이션을 분리하세요:

// 컨테이너: 데이터 처리
export function TaskListContainer() {
  const { tasks, isLoading, error } = useTasks();

  if (isLoading) return <TaskListSkeleton />;
  if (error) return <ErrorState message="작업을 불러오지 못했습니다" retry={refetch} />;
  if (tasks.length === 0) return <EmptyState message="아직 작업이 없습니다" />;

  return <TaskList tasks={tasks} />;
}

// 프레젠테이션: 렌더링 처리
export function TaskList({ tasks }: { tasks: Task[] }) {
  return (
    <ul role="list" className="divide-y">
      {tasks.map(task => <TaskItem key={task.id} task={task} />)}
    </ul>
  );
}

상태 관리

가장 간단한 접근 방식을 선택하세요:

로컬 상태 (useState)           → 컴포넌트별 UI 상태
상태 끌어올리기                     → 2-3개의 형제 컴포넌트 간 공유
컨텍스트                          → 테마, 인증, 로케일 (읽기 위주, 쓰기 드묾)
URL 상태 (searchParams)         → 필터, 페이지네이션, 공유 가능한 UI 상태
서버 상태 (React Query, SWR)  → 캐싱이 있는 원격 데이터
전역 저장소 (Zustand, Redux)    → 앱 전체에서 공유되는 복잡한 클라이언트 상태

3단계 이상의 prop 드릴링은 피하세요. 사용하지 않는 컴포넌트를 통해 props를 전달하고 있다면, 컨텍스트를 도입하거나 컴포넌트 트리를 재구성하세요.

디자인 시스템 준수

참조 기반 UI 품질

제품이 뚜렷한 시각적 방향을 필요로 할 때는 레이아웃을 선택하기 전에 증거를 수집하세요:

  1. 신뢰할 수 있는 참조 카탈로그를 검색하거나 제품 팀이 제공한 참조를 사용하세요.
  2. 관련 화면 2~3개를 연구하세요. 계층 구조, 밀도, 내비게이션, 컨트롤, 반응형 동작, 상호작용 상태에 대한 결정을 기록하세요.
  3. 구현하기 전에 그 결정을 간단한 디자인 계약으로 전환하세요. 화면의 역할, 기본 작업, 필요한 상태, 반응형 규칙, 거부할 패턴을 명명하세요.
  4. 유용한 구조를 제품 자체의 컴포넌트, 토큰, 콘텐츠, 시각적 언어로 재구축하세요. 다른 제품의 브랜딩, 독점 텍스트, 이미지 또는 정확한 레이아웃을 절대 복사하지 마세요.

참조를 템플릿이 아닌 증거로 사용하세요. 참조를 사용할 수 없는 경우, 가정을 문서화하고 결과를 제품의 기존 디자인 시스템에 대해 검증하세요.

AI 미학 피하기

AI 생성 UI는 인식 가능한 패턴을 가지고 있습니다. 모두 피하세요:

AI 기본값문제점프로덕션 품질
모든 것이 보라색/인디고모델이 시각적으로 '안전한' 팔레트를 기본으로 사용하여 모든 앱이 동일하게 보임프로젝트의 실제 색상 팔레트 사용
과도한 그라데이션그라데이션이 시각적 노이즈를 추가하고 대부분의 디자인 시스템과 충돌함디자인 시스템과 일치하는 평면 또는 미묘한 그라데이션
모든 것을 둥글게 (rounded-2xl)최대 둥글기가 '친근함'을 신호하지만 실제 디자인의 모서리 반경 계층 구조를 무시함디자인 시스템의 일관된 border-radius
일반적인 히어로 섹션실제 콘텐츠나 사용자 요구와 관련이 없는 템플릿 기반 레이아웃콘텐츠 우선 레이아웃
Lorem ipsum 스타일 복사본실제 콘텐츠가 드러내는 레이아웃 문제(길이, 줄 바꿈, 오버플로)를 플레이스홀더 텍스트가 숨김현실적인 플레이스홀더 콘텐츠
모든 곳에 과도한 패딩동일한 넉넉한 패딩이 시각적 계층 구조를 파괴하고 화면 공간을 낭비함일관된 간격 척도
기본 카드 그리드균일한 그리드는 정보 우선 순위와 스캔 패턴을 무시하는 레이아웃 지름길임목적 기반 레이아웃
그림자 과다 디자인계층화된 그림자는 콘텐츠와 경쟁하고 저사양 기기에서 렌더링을 느리게 함디자인 시스템에서 지정하지 않는 한 미묘하거나 그림자 없음

간격 및 레이아웃

일관된 간격 척도를 사용하세요. 값을 임의로 만들지 마세요:

/* 척도 사용: 0.25rem 단위 (또는 프로젝트가 사용하는 것) */
/* 좋음 */  padding: 1rem;      /* 16px */
/* 좋음 */  gap: 0.75rem;       /* 12px */
/* 나쁨 */   padding: 13px;      /* 어떤 척도에도 없음 */
/* 나쁨 */   margin-top: 2.3rem; /* 어떤 척도에도 없음 */

타이포그래피

타입 계층 구조를 존중하세요:

h1 → 페이지 제목 (페이지당 한 개)
h2 → 섹션 제목
h3 → 하위 섹션 제목
body → 기본 텍스트
small → 보조/도움말 텍스트

제목 수준을 건너뛰지 마세요. 제목이 아닌 콘텐츠에 제목 스타일을 사용하지 마세요.

색상

  • 의미론적 색상 토큰 사용: text-primary, bg-surface, border-default — 원시 hex 값 사용 금지
  • 충분한 대비 보장 (일반 텍스트의 경우 4.5:1, 큰 텍스트의 경우 3:1)
  • 정보를 전달하는 데 색상에만 의존하지 마세요 (아이콘, 텍스트 또는 패턴도 사용)

접근성 (WCAG 2.1 AA)

모든 컴포넌트는 다음 기준을 충족해야 합니다:

키보드 내비게이션

// 모든 상호작용 요소는 키보드로 접근 가능해야 함
<button onClick={handleClick}>클릭하세요</button>        // ✓ 기본적으로 포커스 가능
<div onClick={handleClick}>클릭하세요</div>               // ✗ 포커스 불가능
<div role="button" tabIndex={0} onClick={handleClick}    // ✓ 하지만 <button> 권장
     onKeyDown={e => {
       if (e.key === 'Enter') handleClick();
       if (e.key === ' ') e.preventDefault();
     }}
     onKeyUp={e => {
       if (e.key === ' ') handleClick();
     }}>
  클릭하세요
</div>

ARIA 레이블

// 보이는 텍스트가 없는 상호작용 요소에 레이블 지정
<button aria-label="대화상자 닫기"><XIcon /></button>

// 폼 입력에 레이블 지정
<label htmlFor="email">이메일</label>
<input id="email" type="email" />

// 또는 보이는 레이블이 없는 경우 aria-label 사용
<input aria-label="작업 검색" type="search" />

포커스 관리

// 콘텐츠 변경 시 포커스 이동
function Dialog({ isOpen, onClose }: DialogProps) {
  const closeRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    if (isOpen) closeRef.current?.focus();
  }, [isOpen]);

  // 열려 있을 때 대화상자 내부에 포커스 고정
  return (
    <dialog open={isOpen}>
      <button ref={closeRef} onClick={onClose}>닫기</button>
      {/* 대화상자 콘텐츠 */}
    </dialog>
  );
}

의미 있는 빈 상태 및 오류 상태

// 빈 화면을 표시하지 마세요
function TaskList({ tasks }: { tasks: Task[] }) {
  if (tasks.length === 0) {
    return (
      <div role="status" className="text-center py-12">
        <TasksEmptyIcon className="mx-auto h-12 w-12 text-muted" />
        <h3 className="mt-2 text-sm font-medium">작업 없음</h3>
        <p className="mt-1 text-sm text-muted">새 작업을 만들어 시작하세요.</p>
        <Button className="mt-4" onClick={onCreateTask}>작업 만들기</Button>
      </div>
    );
  }

  return <ul role="list">...</ul>;
}

반응형 디자인

모바일 우선으로 디자인한 다음 확장하세요:

// Tailwind: 모바일 우선 반응형
<div className="
  grid grid-cols-1      /* 모바일: 단일 열 */
  sm:grid-cols-2        /* 소형: 2열 */
  lg:grid-cols-3        /* 대형: 3열 */
  gap-4
">

다음 중단점에서 테스트하세요: 320px, 768px, 1024px, 1440px.

로딩 및 전환

// 스켈레톤 로딩 (콘텐츠에 스피너 사용 금지)
function TaskListSkeleton() {
  return (
    <div className="space-y-3" aria-busy="true" aria-label="작업 로딩 중">
      {Array.from({ length: 3 }).map((_, i) => (
        <div key={i} className="h-12 bg-muted animate-pulse rounded" />
      ))}
    </div>
  );
}

// 인지된 속도를 위한 낙관적 업데이트
function useToggleTask() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: toggleTask,
    onMutate: async (taskId) => {
      await queryClient.cancelQueries({ queryKey: ['tasks'] });
      const previous = queryClient.getQueryData(['tasks']);

      queryClient.setQueryData(['tasks'], (old: Task[]) =>
        old.map(t => t.id === taskId ? { ...t, done: !t.done } : t)
      );

      return { previous };
    },
    onError: (_err, _taskId, context) => {
      queryClient.setQueryData(['tasks'], context?.previous);
    },
  });
}

참조

자세한 접근성 요구 사항 및 테스트 도구는 ../../references/accessibility-checklist.md를 참조하세요.

일반적인 합리화

합리화현실
"접근성은 있으면 좋은 기능이다"많은 관할권에서 법적 요구 사항이자 엔지니어링 품질 기준입니다.
"나중에 반응형으로 만들겠다"반응형 디자인을 다시 적용하는 것은 처음부터 구축하는 것보다 3배 더 어렵습니다.
"디자인이 최종본이 아니므로 스타일링을 건너뛰겠다"디자인 시스템 기본값을 사용하세요. 스타일이 없는 UI는 리뷰어에게 좋지 않은 첫인상을 줍니다.
"이건 그냥 프로토타입이다"프로토타입은 프로덕션 코드가 됩니다. 기초를 올바르게 구축하세요.
"AI 미학은 지금은 괜찮다"이는 낮은 품질을 신호합니다. 처음부터 프로젝트의 실제 디자인 시스템을 사용하세요.

위험 신호

  • 200줄이 넘는 컴포넌트 (분할하세요)
  • 인라인 스타일 또는 임의의 픽셀 값
  • 오류 상태, 로딩 상태 또는 빈 상태 누락
  • 키보드 내비게이션 테스트 없음
  • 상태의 유일한 지표로 색상을 사용(텍스트나 아이콘 없이 빨간색/녹색)
  • 일반적인 "AI 룩" (보라색 그라데이션, 과도하게 큰 카드, 기본 레이아웃)

검증

UI 구축 후:

  • 컴포넌트가 콘솔 오류 없이 렌더링됨
  • 모든 상호작용 요소가 키보드로 접근 가능함 (Tab 키로 페이지 탐색)
  • 스크린 리더가 페이지의 콘텐츠와 구조를 전달할 수 있음
  • 반응형: 320px, 768px, 1024px, 1440px에서 작동함
  • 해당되는 경우 로딩, 빈, 오류, 성공 및 권한 상태가 처리됨
  • 프로젝트의 디자인 시스템(간격, 색상, 타이포그래피)을 따름
  • 렌더링된 결과가 최종 UI 특정 마감 게이트 검토를 통과함
  • 개발자 도구 또는 axe-core에서 접근성 경고 없음

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

addyosmani/agent-skills

Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.

addyosmani/agent-skills

Prepares production launches. Use when preparing to deploy to production, or when asking what needs to be in place before shipping. Use when you need a pre-launch checklist, when setting up monitoring, when planning a staged rollout, or when you need a rollback strategy.

addyosmani/browser-testing-with-devtools

Tests in real browsers via Chrome DevTools MCP. Use when building or debugging anything that runs in a browser. Use when you need to inspect the DOM, capture console errors, analyze network requests, profile performance, or verify visual output with real runtime data. Requires the chrome-devtools MCP server to be configured.

addyosmani/ci-cd-and-automation

Automates CI/CD pipeline setup. Use when setting up or modifying build and deployment pipelines. Use when you need to automate quality gates, configure test runners in CI, or establish deployment strategies.

addyosmani/code-review-and-quality

Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.

addyosmani/code-simplification

Simplifies code for clarity. Use when refactoring code for clarity without changing behavior. Use when code works but is harder to read, maintain, or extend than it should be. Use when reviewing code that has accumulated unnecessary complexity.

addyosmani/constraint-driven-development

Establishes a project's quality bar as a written contract and stops agents quietly lowering it. Interviews the user on which dimensions matter, supplies sane default thresholds when they have no number in mind, records everything in CONSTRAINTS.md, and watches the diff for a weakened bar — new @ts-ignore or eslint-disable suppressions, skipped or deleted tests, assertions stripped out, unimplemented stubs, thresholds edited down. Use when no quality bar is written down, when the user says "set up constraints" or "define our standards", when the user wants dimensions they care about — accessibility, web performance, coverage — set up as enforced constraints, when an agent keeps silencing checks or skipping tests to get to green, when you need a coverage or performance threshold and don't know what number to pick, or when an agent writes more code than anyone will read.

addyosmani/debugging-and-error-recovery

Guides systematic root-cause debugging. Use when tests fail, builds break, behavior doesn't match expectations, or you encounter any unexpected error. Use when you need a systematic approach to finding and fixing the root cause rather than guessing.

addyosmani/deprecation-and-migration

Manages deprecation and migration. Use when removing old systems, APIs, or features. Use when migrating users from one implementation to another. Use when deciding whether to maintain or sunset existing code.

addyosmani/documentation-and-adrs

Records decisions and documentation. Use when making architectural decisions, changing public APIs, shipping features, or when you need to record context that future engineers and agents will need to understand the codebase.

addyosmani/doubt-driven-development

Subjects every non-trivial decision to a fresh-context adversarial review before it stands. Use when correctness matters more than speed, when working in unfamiliar code, when stakes are high (production, security-sensitive logic, irreversible operations), or any time a confident output would be cheaper to verify now than to debug later.

addyosmani/git-workflow-and-versioning

Structures git workflow practices. Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams.

addyosmani/idea-refine

Refines raw ideas into sharp, actionable concepts through structured divergent and convergent thinking. Use when an idea is still vague, when you need to stress-test assumptions before committing to a plan, or when you want to expand options before converging on one. Triggers on "ideate", "refine this idea", or "stress-test my plan".

addyosmani/incremental-implementation

Delivers changes incrementally. Use when implementing any feature or change that touches more than one file. Use when you're about to write a large amount of code at once, or when a task feels too big to land in one step.

addyosmani/interview-me

Extracts what the user actually wants instead of what they think they should want. Achieves this through one-question-at-a-time interview until ~95% confidence about the underlying intent. Use when an ask is underspecified ("build me X" without "for whom" or "why now"), when the user explicitly invokes ("interview me", "grill me", "are we sure?", "stress-test my thinking"), or when you catch yourself silently filling in ambiguous requirements before any plan, spec, or code exists.

addyosmani/observability-and-instrumentation

Instruments code so production behavior is visible and diagnosable. Use when adding logging, metrics, tracing, or alerting. Use when shipping any feature that runs in production and you need evidence it works. Use when production issues are reported but you can't tell what happened from the available data.

addyosmani/performance-optimization

Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.

addyosmani/planning-and-task-breakdown

Breaks work into ordered tasks. Use when you have a spec or clear requirements and need to break work into implementable tasks. Use when a task feels too large to start, when you need to estimate scope, or when parallel work is possible.

addyosmani/security-and-hardening

Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.

addyosmani/source-driven-development

Grounds every implementation decision in official documentation. Use when you want authoritative, source-cited code free from outdated patterns. Use when building with any framework or library where correctness matters.

관련 스킬