Claude 코드 스킬로 UI 구축하는 방법

Ashley Goolam

Ashley Goolam

21 January 2026

Claude 코드 스킬로 UI 구축하는 방법

새로운 기능마다 UI 구성 요소를 Claude Code에 수동으로 설명하는 것은 클래스 없이 CSS를 작성하는 것과 같습니다. 반복적이고 일관성이 없으며 팀 전체에 걸쳐 확장하기 불가능합니다. UI 구축을 위한 Claude Code Skills는 디자인 시스템을 예측 가능한 매개변수와 제로 상용구로 구성 요소, 레이아웃 및 스타일을 생성하는 실행 가능한 도구로 전환합니다.

UI 구축을 위한 Claude Code Skills란?

Claude Code Skills는 UI 생성 로직을 재사용 가능하고 버전 관리되는 도구로 패키징하여 Claude Code가 Model Context Protocol (MCP)을 통해 검색하고 호출할 수 있도록 합니다. "Tailwind, 왼쪽 정렬 이미지, 오른쪽 정렬 텍스트, 기본 버튼이 있는 반응형 카드 구성 요소를 만드세요"와 같이 장황한 프롬프트를 작성하는 대신, building-ui 스킬을 한 번 정의하고 component: "card", layout: "image-left"와 같은 간결한 매개변수로 호출합니다.

각 스킬은 다음을 정의하는 SKILL.md 파일로 구성됩니다.

공식 저장소의 building-ui 스킬은 구성 요소, 레이아웃, 테마 및 양식에 대한 패턴을 제공합니다. 이는 임시 UI 생성을 체계적이고 반복 가능한 프로세스로 전환합니다.

claude code skills

원시 프롬프트에 비해 주요 장점

💡
멋진 API 문서를 생성하는 훌륭한 API 테스트 도구를 원하십니까?

최대 생산성으로 개발자 팀이 협력할 수 있는 통합된 올인원 플랫폼을 원하십니까?

Apidog는 모든 요구 사항을 충족하며 훨씬 더 저렴한 가격으로 Postman을 대체합니다!
button

building-ui 스킬 설정

1단계: Claude Code 설치 및 MCP 활성화

Claude Code CLI를 설치하지 않은 경우:

npm install -g @anthropic-ai/claude-code
claude --version  # 2.0.70 이상이어야 함

MCP 구성 디렉토리 및 파일을 생성하십시오:

# macOS/Linux
mkdir -p ~/.config/claude-code
touch ~/.config/claude-code/config.json

# Windows
mkdir %APPDATA%\claude-code
echo {} > %APPDATA%\claude-code\config.json
claude code

2단계: building-ui 스킬 복제 및 빌드

git clone https://github.com/anthropics/skills.git
cd skills/skills/building-ui
npm install
npm run build

이렇게 하면 TypeScript 핸들러가 dist/index.js로 컴파일됩니다.

3단계: 스킬 로드를 위한 MCP 구성

~/.config/claude-code/config.json 편집:

{
  "mcpServers": {
    "building-ui": {
      "command": "node",
      "args": ["/absolute/path/to/skills/building-ui/dist/index.js"],
      "env": {
        "UI_LIBRARY": "react",
        "STYLE_SYSTEM": "tailwind",
        "THEME_CONFIG": "~/project/design-tokens.json"
      }
    }
  }
}

중요:

4단계: 설치 확인

claude

로드되면 다음을 실행하십시오:

/list-tools

다음이 표시되어야 합니다:

Available tools:
- building-ui:generate-component
- building-ui:create-layout
- building-ui:apply-theme
- building-ui:generate-form

도구가 표시되지 않으면 로그를 확인하십시오:

# macOS/Linux
tail -f ~/.cache/claude-code/logs/mcp.log

# Windows
type %APPDATA%\claude-code\logs\mcp.log

일반적인 문제:

스킬을 사용한 핵심 UI 구축 패턴

building-ui 스킬은 네 가지 주요 도구를 내보냅니다. 각 도구는 구조화된 매개변수를 허용하고 생성된 코드를 반환합니다.

1. 구성 요소 생성 도구

도구 이름: building-ui:generate-component
사용 사례: 재사용 가능한 UI 구성 요소 생성

매개변수:

예시: 변형이 있는 버튼 생성

generate-component 도구를 사용하여 기본, 보조, 윤곽선 변형, 중간 크기, 비활성화 상태를 지원하는 버튼 구성 요소를 생성합니다.

생성된 출력 (React + Tailwind):

// Button.tsx
import React from 'react';
import clsx from 'clsx';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'outline';
  size?: 'small' | 'medium' | 'large';
}

export const Button: React.FC<ButtonProps> = ({ 
  variant = 'primary', 
  size = 'medium',
  disabled,
  children,
  className,
  ...props 
}) => {
  const baseClasses = 'font-semibold rounded-lg transition-colors';
  const variantClasses = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
    outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50'
  };
  const sizeClasses = {
    small: 'px-3 py-1.5 text-sm',
    medium: 'px-4 py-2 text-base',
    large: 'px-6 py-3 text-lg'
  };
  
  return (
    <button
      disabled={disabled}
      className={clsx(
        baseClasses,
        variantClasses[variant],
        sizeClasses[size],
        disabled && 'opacity-50 cursor-not-allowed',
        className
      )}
      {...props}
    >
      {children}
    </button>
  );
};

스킬은 환경 변수를 기반으로 TypeScript 유형, 접근성 속성 및 스타일링 클래스를 추론합니다.

2. 레이아웃 생성 도구

도구 이름: building-ui:create-layout
사용 사례: 반응형 페이지 레이아웃 생성

매개변수:

예시: 반응형 사이드바가 있는 대시보드 레이아웃

create-layout을 사용하여 접을 수 있는 사이드바, 헤더, 기본 콘텐츠 영역 및 푸터가 있는 반응형 대시보드 레이아웃을 생성합니다. gap-4를 사용하고 데스크톱에서는 사이드바를 256px 너비로, 모바일에서는 전체 너비로 만듭니다.

생성된 출력:

// DashboardLayout.tsx
import React, { useState } from 'react';
import clsx from 'clsx';

interface DashboardLayoutProps {
  header?: React.ReactNode;
  sidebar?: React.ReactNode;
  main: React.ReactNode;
  footer?: React.ReactNode;
}

export const DashboardLayout: React.FC<DashboardLayoutProps> = ({ 
  header, 
  sidebar, 
  main, 
  footer 
}) => {
  const [sidebarOpen, setSidebarOpen] = useState(false);

  return (
    <div className="min-h-screen flex flex-col">
      {/* Header */}
      <header className="bg-white shadow-sm border-b border-gray-200 z-10">
        <div className="px-4 sm:px-6 lg:px-8 py-4">
          {header}
        </div>
      </header>

      <div className="flex flex-1">
        {/* Mobile menu button */}
        <button
          className="lg:hidden fixed bottom-4 right-4 bg-blue-600 text-white p-3 rounded-full shadow-lg z-20"
          onClick={() => setSidebarOpen(!sidebarOpen)}
        >
          ☰
        </button>

        {/* Sidebar */}
        <aside className={clsx(
          'bg-gray-50 border-r border-gray-200',
          'fixed lg:relative inset-y-0 left-0 z-30',
          'w-64 transform transition-transform lg:translate-x-0',
          sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'
        )}>
          <div className="p-4">
            {sidebar}
          </div>
        </aside>

        {/* Main content */}
        <main className="flex-1 p-4 sm:p-6 lg:p-8">
          {main}
        </main>
      </div>

      {/* Footer */}
      {footer && (
        <footer className="bg-gray-50 border-t border-gray-200 mt-auto">
          <div className="px-4 sm:px-6 lg:px-8 py-4">
            {footer}
          </div>
        </footer>
      )}
    </div>
  );
};

스킬은 모바일 메뉴 로직, 중단점 인식 클래스 및 접근성 속성을 자동으로 추가합니다.

3. 테마 적용 도구

도구 이름: building-ui:apply-theme
사용 사례: 구성 요소에 디자인 토큰 적용

매개변수:

예시: 카드 구성 요소에 어두운 테마 적용

apply-theme을 사용하여 슬레이트 색상 팔레트, 간격 스케일 4, Inter 글꼴 계열로 어두운 모드용 카드 구성 요소를 구성합니다.

생성된 출력:

// card-theme.ts
export const cardTheme = {
  light: {
    background: 'bg-white',
    border: 'border-gray-200',
    text: 'text-gray-900',
    subText: 'text-gray-600'
  },
  dark: {
    background: 'bg-slate-800',
    border: 'border-slate-700',
    text: 'text-slate-100',
    subText: 'text-slate-400'
  }
};

// Card.tsx에서 사용
import { cardTheme } from './card-theme';

interface CardProps {
  variant?: 'light' | 'dark';
  children: React.ReactNode;
}

export const Card: React.FC<CardProps> = ({ variant = 'light', children }) => {
  const theme = cardTheme[variant];
  
  return (
    <div className={clsx(
      'rounded-lg p-4 border',
      theme.background,
      theme.border
    )}>
      {children}
    </div>
  );
};

스킬은 THEME_CONFIG 파일을 읽고 테마별 토큰 맵을 생성합니다. THEME_CONFIG가 JSON 파일을 가리키는 경우:

{
  "colors": {
    "primary": "#3B82F6",
    "secondary": "#6B7280"
  },
  "fonts": {
    "sans": "Inter",
    "mono": "JetBrains Mono"
  }
}

생성된 코드는 Tailwind 기본값 대신 이러한 정확한 값을 사용합니다.

4. 양식 생성 도구

도구 이름: building-ui:generate-form
사용 사례: 스키마에서 유효성 검사된 양식 생성

매개변수:

예시: 유효성 검사가 있는 사용자 등록 양식

generate-form을 사용하여 이름(텍스트, 필수), 이메일(이메일, 필수), 비밀번호(비밀번호, 최소 길이 8), 약관 동의(체크박스) 필드가 있는 사용자 등록 양식을 생성합니다. onBlur 유효성 검사를 사용하여 /api/register로 제출합니다.

생성된 출력:

// UserRegistrationForm.tsx
import React, { useState } from 'react';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm, SubmitHandler } from 'react-hook-form';

const schema = z.object({
  name: z.string().min(1, 'Name is required'),
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
  acceptTerms: z.boolean().refine(val => val === true, {
    message: 'You must accept the terms'
  })
});

type FormData = z.infer<typeof schema>;

export const UserRegistrationForm: React.FC = () => {
  const [isSubmitting, setIsSubmitting] = useState(false);
  
  const {
    register,
    handleSubmit,
    formState: { errors },
    trigger
  } = useForm<FormData>({
    resolver: zodResolver(schema),
    mode: 'onBlur'
  });

  const onSubmit: SubmitHandler<FormData> = async (data) => {
    setIsSubmitting(true);
    try {
      const response = await fetch('/api/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data)
      });
      
      if (!response.ok) throw new Error('Registration failed');
      
      // Handle success
      console.log('User registered:', await response.json());
    } catch (error) {
      console.error('Registration error:', error);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)} className="space-y-4 max-w-md">
      <div>
        <label htmlFor="name" className="block text-sm font-medium text-gray-700">
          Name
        </label>
        <input
          id="name"
          {...register('name')}
          className={clsx(
            'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500',
            errors.name && 'border-red-500'
          )}
        />
        {errors.name && (
          <p className="mt-1 text-sm text-red-600">{errors.name.message}</p>
        )}
      </div>

      <div>
        <label htmlFor="email" className="block text-sm font-medium text-gray-700">
          Email
        </label>
        <input
          id="email"
          type="email"
          {...register('email')}
          className={clsx(
            'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500',
            errors.email && 'border-red-500'
          )}
        />
        {errors.email && (
          <p className="mt-1 text-sm text-red-600">{errors.email.message}</p>
        )}
      </div>

      <div>
        <label htmlFor="password" className="block text-sm font-medium text-gray-700">
          Password
        </label>
        <input
          id="password"
          type="password"
          {...register('password')}
          className={clsx(
            'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500',
            errors.password && 'border-red-500'
          )}
        />
        {errors.password && (
          <p className="mt-1 text-sm text-red-600">{errors.password.message}</p>
        )}
      </div>

      <div className="flex items-center">
        <input
          id="acceptTerms"
          type="checkbox"
          {...register('acceptTerms')}
          className="h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
        />
        <label htmlFor="acceptTerms" className="ml-2 block text-sm text-gray-900">
          I accept the terms and conditions
        </label>
      </div>
      {errors.acceptTerms && (
        <p className="text-sm text-red-600">{errors.acceptTerms.message}</p>
      )}

      <button
        type="submit"
        disabled={isSubmitting}
        className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
      >
        {isSubmitting ? 'Registering...' : 'Register'}
      </button>
    </form>
  );
};

스킬은 react-hook-form, zod 유효성 검사, 접근성 속성 및 로딩 상태를 자동으로 연결합니다.

고급 기술을 사용한 동적 UI 생성

조건부 렌더링 로직

일부 UI는 매개변수에 따라 조건부 섹션이 필요합니다. 스킬은 필드 정의에서 conditions를 지원합니다:

"accountType"이 "business"인 경우에만 "company" 필드가 나타나는 사용자 프로필 양식을 생성합니다.

이렇게 하면 조건부 렌더링이 포함된 양식이 생성됩니다:

{accountType === 'business' && (
  <div>
    <label htmlFor="company">Company</label>
    <input id="company" {...register('company')} />
  </div>
)}

구성 요소 구성

스킬 호출을 연결하여 복잡한 UI를 구축합니다:

먼저 사이드바와 헤더가 있는 DashboardLayout 구성 요소를 생성합니다. 그런 다음, 메트릭을 위한 StatCard 구성 요소를 생성합니다. 마지막으로 둘 다에 어두운 테마를 적용합니다.

Claude Code는 이를 순차적으로 실행하여 호출 간에 컨텍스트를 전달합니다. 레이아웃 구성 요소는 카드 생성 시 사용 가능하며 적절한 통합을 보장합니다.

런타임 테마 전환

테마 인식 코드를 내보내도록 스킬을 구성하십시오:

{
  "building-ui": {
    "command": "node",
    "args": ["dist/index.js"],
    "env": {
      "UI_LIBRARY": "react",
      "STYLE_SYSTEM": "tailwind",
      "THEME_CONFIG": "~/project/themes.json",
      "SUPPORT_THEME_TOGGLE": "true"
    }
  }
}

이제 생성된 구성 요소에는 ThemeProvider 래퍼가 포함됩니다:

// App.tsx
import { ThemeProvider } from './ThemeProvider';
import { DashboardLayout } from './DashboardLayout';

function App() {
  return (
    <ThemeProvider defaultTheme="light" enableSystem>
      <DashboardLayout />
    </ThemeProvider>
  );
}

UI 구축 스킬 디버깅 및 반복

.claude-cache에서 생성된 코드 보기

Claude Code는 스킬 출력을 캐시합니다. 다음을 통해 검사하십시오:

# macOS/Linux
cat ~/.cache/claude-code/last-skill-output.tsx

# Windows
type %APPDATA%\claude-code\last-skill-output.tsx

생성된 코드가 예상과 일치하지 않으면 매개변수를 구체화하십시오. 더 구체적으로 추가하십시오:

대신: "카드 생성"
사용: "16px 패딩, 8px 테두리 반경, 미묘한 상자 그림자가 있는 카드 생성"

프로젝트별 스킬 기본값 재정의

프로젝트 루트에 .claude-ui-config.json을 생성하십시오:

{
  "uiLibrary": "vue",
  "styleSystem": "css-modules",
  "themeConfig": "./design-tokens.json"
}

이것은 해당 프로젝트에 대해서만 전역 MCP 설정을 재정의합니다.

스킬 버전 관리

building-ui 스킬을 업데이트할 때 버전을 태그하십시오:

cd skills/building-ui
npm version patch  # 또는 minor/major
git tag -a v1.1.0 -m "Vue 3.5 지원 추가"

버전 고정을 위해 Claude Code 구성을 업데이트하십시오:

{
  "mcpServers": {
    "building-ui": {
      "command": "node",
      "args": ["/path/to/skills/building-ui-v1.1.0/dist/index.js"]
    }
  }
}

이렇게 하면 프로덕션 워크플로우에 영향을 미치는 변경 사항이 발생하지 않습니다.

결론

UI 구축을 위한 Claude Code Skills는 자연어를 정밀하게 프로덕션 준비가 된 구성 요소, 레이아웃, 테마 및 양식으로 변환합니다. 설정에 15분만 투자하면 디자인 일관성을 유지하고 상용구를 제거하며 기능 개발을 가속화하는 재사용 가능한 툴킷을 얻을 수 있습니다. 네 가지 핵심 도구(구성 요소 생성, 레이아웃 생성, 테마 적용, 양식 생성)로 시작하여 특정 디자인 시스템에 맞게 확장하십시오.

스킬이 API를 사용하는 UI를 생성할 때 Apidog로 해당 엔드포인트를 유효성 검사하여 AI로 구축된 인터페이스가 신뢰할 수 있는 백엔드와 통신하는지 확인하십시오.

button

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요