☰ Categories

Component Documentation

a design systems documentarian creating the component specification for a CLAUDE.md file.

CategoryDevelopment › Technical writing
TagsDraftingDeveloperCodeTemplate
Prompt
You are a design systems documentarian creating the component specification
for a CLAUDE.md file. This documentation will be used by AI coding assistants
(Claude, Cursor, Copilot) to generate consistent UI code.

## Context
- **Token system:** [Paste or reference Phase 2 output]
- **Component to document:** [Component name, or "all components from inventory"]
- **Framework:** [Next.js + React + Tailwind / etc.]

## For Each Component, Document:

### 1. Overview
- Component name (PascalCase)
- One-line description
- Category (Navigation / Input / Feedback / Layout / Data Display)

### 2. Anatomy
- List every visual part (e.g., Button = container + label + icon-left + icon-right)
- Which parts are optional vs required
- Nesting rules (what can/cannot go inside this component)

### 3. Props Specification
For each prop:
- Name, type, default value, required/optional
- Allowed values (if enum)
- Brief description of what it controls visually
- Example usage

### 4. Visual Variants
- Size variants with exact token values (padding, font-size, height)
- Color variants with exact token references
- State variants: default, hover, active, focus, disabled, loading, error
- For EACH state: specify which tokens change and to what values

### 5. Token Consumption Map
Component: Button
├── background → button-bg-${variant} → color-brand-${shade}
├── text-color → button-text-${variant} → color-white
├── padding-x → button-padding-x-${size} → spacing-{n}
├── padding-y → button-padding-y-${size} → spacing-{n}
├── border-radius → button-radius → radius-md
├── font-size → button-font-${size} → font-size-{n}
├── font-weight → button-font-weight → font-weight-semibold
└── transition → motion-duration-fast + motion-ease-default

### 6. Usage Guidelines
- When to use (and when NOT to use — suggest alternatives)
- Maximum instances per viewport (e.g., "only 1 primary CTA per section")
- Content guidelines (label length, capitalization, icon usage)

### 7. Accessibility
- Required ARIA attributes
- Keyboard interaction pattern
- Focus management rules
- Screen reader behavior
- Minimum contrast ratios met by default tokens

### 8. Code Example
Provide a copy-paste-ready code example using the actual codebase's
patterns (import paths, className conventions, etc.)

## Output Format

Markdown, structured with headers per section. This will be directly
inserted into the CLAUDE.md file.

What this prompt does

This is useful for documenting design-system components for AI coding tools. It asks for anatomy, props, state-specific tokens, accessibility, and code examples aligned with the actual codebase patterns.

Model comparison

ChatGPT is the most complete and faithful to the supplied tokens. Gemini is well organized but inaccurate and incomplete, while [C] was not provided.

ChatGPTTop overall
43/ 50

+ Covers all eight sections with concrete token mappings.

- The Slot/link disabled handling and undefined tokens are problematic.

Gemini
29/ 50

+ Tables and state matrices make detailed rules easy to scan.

- The code is truncated and invents tokens while misstating contrast.

CriterionChatGPTGeminiLeader
Instruction following95ChatGPT +80%
Accuracy85ChatGPT +60%
Specificity97ChatGPT +29%
Structure98ChatGPT +13%
Right length84ChatGPT +100%

Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-24). This is an AI review, not a measurement.

Read full answers

We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.

Input used
[Pasted material]
Token system (Phase 2 산출물):
- color-brand-500: #2563EB, color-brand-600: #1D4ED8
- spacing-1~8: 4px 단위로 4px~32px
- radius-md: 8px, radius-lg: 12px
- font-size-sm/base/lg: 14px/16px/18px

Component to document: Button
Framework: Next.js 14 + React + TailwindCSS (shadcn/ui 기반)
gpt-5.6-luna (codex CLI · 에이전트 하네스) · Run on 2026-09-24

Button

1. 개요

  • 컴포넌트명: Button
  • 설명: 사용자의 작업을 실행하거나 다음 단계로 이동시키는 클릭 가능한 액션 컨트롤
  • 카테고리: Input / Navigation

기본 프레임워크는 Next.js 14, React, TailwindCSS, shadcn/ui의 cva 및 Slot 패턴을 따른다.


2. Anatomy

Button
├── interactive container
├── icon-left      optional
├── label          required, icon-only일 때는 visually hidden 가능
├── icon-right     optional
└── loading indicator optional

필수 요소

  • 클릭 가능한 컨테이너
  • 일반 버튼인 경우 visible label
  • 아이콘만 사용하는 경우 aria-label 또는 sr-only 접근성 이름

선택 요소

  • 왼쪽 아이콘
  • 오른쪽 아이콘
  • 로딩 스피너
  • 키보드 단축키 표시

Nesting rules

  • 기본적으로 텍스트, 아이콘, 로딩 인디케이터만 포함한다.
  • 버튼 안에 다른 <button>, <a>, 입력 필드 또는 인터랙티브 요소를 중첩하지 않는다.
  • 링크 이동이 목적이면 Button보다 Link를 사용한다.
  • asChild 사용 시 단일 React element만 자식으로 전달한다.

3. Props Specification

Prop Type Default Required 설명
variant "default" | "outline" | "ghost" | "destructive" "default" Optional 버튼의 색상 및 시각적 강조 수준
size "sm" | "default" | "lg" | "icon" "default" Optional 버튼의 높이, 패딩, 글자 크기
asChild boolean false Optional 자식 요소의 태그와 동작을 유지하면서 Button 스타일을 적용
loading boolean false Optional 로딩 상태 표시 및 중복 클릭 방지
disabled boolean false Optional 버튼 비활성화
className string undefined Optional 추가 Tailwind 클래스
children React.ReactNode — Required 버튼 내용
type "button" | "submit" | "reset" "button" Optional 폼 내 버튼의 동작
aria-label string undefined Conditional 아이콘 전용 버튼의 접근성 이름

사용 예시

<Button variant="default" size="default">
  저장
</Button>

<Button variant="outline" loading>
  저장 중
</Button>

<Button size="icon" aria-label="설정 열기">
  <Settings className="size-4" />
</Button>

<Button asChild>
  <Link href="/settings">설정</Link>
</Button>

4. Visual Variants

Size variants

Size Height Padding X Padding Y Font size 아이콘
sm 32px spacing-3 = 12px spacing-2 = 8px font-size-sm = 14px 16px
default 40px spacing-4 = 16px spacing-2 = 8px font-size-base = 16px 16px
lg 48px spacing-6 = 24px spacing-3 = 12px font-size-lg = 18px 20px
icon 40px 0px 0px — 16px
  • border-radius: radius-md = 8px
  • font-weight: font-weight-semibold = 600
  • gap: spacing-2 = 8px
  • transition: motion-duration-fast + motion-ease-default

Color variants

Variant Default Hover Active Text
default color-brand-500 = #2563EB color-brand-600 = #1D4ED8 color-brand-600 = #1D4ED8 color-white
outline transparent + color-brand-500 border color-brand-500 background color-brand-600 background color-brand-600
ghost transparent color-brand-500 at 10% opacity color-brand-500 at 15% opacity color-brand-600
destructive color-error-500 color-error-600 color-error-600 color-white

destructive와 ghost에 필요한 color-error-*, 투명도 토큰은 Phase 2 토큰 시스템에 추가하거나 프로젝트의 기존 semantic token으로 매핑한다.

State variants

State 변경 토큰
Default button-bg-{variant}, button-text-{variant}, button-radius, size별 padding/font
Hover 배경을 color-brand-600으로 변경. outline은 color-brand-500 배경으로 변경
Active 배경을 color-brand-600으로 변경하고 transform: translateY(1px) 적용 가능
Focus-visible ring-width-2, ring-color-brand-500, ring-offset-2 적용
Disabled opacity-50, cursor-not-allowed, hover/active 스타일 제거
Loading 기존 label의 시각적 투명도 감소, loading-indicator 표시, 클릭 방지
Error color-error-* border/background/text 및 aria-invalid="true" 적용

로딩 상태에서는 disabled와 동일하게 키보드 및 포인터 입력을 차단한다.


5. Token Consumption Map

Button
├── background
│   └── button-bg-${variant}
│       ├── default → color-brand-500
│       └── hover/active → color-brand-600
├── text-color
│   └── button-text-${variant}
│       ├── default → color-white
│       └── outline/ghost → color-brand-600
├── border-color
│   └── button-border-${variant}
│       └── outline → color-brand-500
├── padding-x
│   └── button-padding-x-${size}
│       ├── sm → spacing-3
│       ├── default → spacing-4
│       └── lg → spacing-6
├── padding-y
│   └── button-padding-y-${size}
│       ├── sm/default → spacing-2
│       └── lg → spacing-3
├── height
│   ├── sm → 32px
│   ├── default/icon → 40px
│   └── lg → 48px
├── border-radius
│   └── button-radius → radius-md
├── font-size
│   ├── sm → font-size-sm
│   ├── default → font-size-base
│   └── lg → font-size-lg
├── font-weight
│   └── button-font-weight → font-weight-semibold
├── icon-size
│   ├── sm/default → 16px
│   └── lg → 20px
└── transition
    └── motion-duration-fast + motion-ease-default

6. Usage Guidelines

사용해야 하는 경우

  • 저장, 제출, 삭제, 추가, 확인 등 명확한 액션
  • 모달의 확인/취소 동작
  • 사용자를 다음 화면으로 이동시키는 주요 CTA

사용하지 않아야 하는 경우

  • 단순 페이지 이동: Link 사용
  • 여러 옵션 중 하나를 선택: Select, RadioGroup, Tabs 사용
  • 즉시 실행이 아닌 메뉴 열기: DropdownMenuTrigger 사용
  • 긴 설명이나 문장이 필요한 경우: 버튼 라벨을 짧게 유지하고 설명은 주변 텍스트로 분리

인스턴스 제한

  • 한 화면 또는 주요 섹션에는 default 스타일의 Primary CTA를 최대 1개만 둔다.
  • 모달에는 Primary CTA 1개와 Secondary/Cancel 액션 1개를 권장한다.
  • 같은 영역에 동일한 강조도의 버튼을 3개 이상 배치하지 않는다.

콘텐츠 가이드

  • 라벨은 동사 중심으로 작성한다: 저장, 계속, 초대 보내기
  • 문장 첫 글자만 대문자로 처리하고, 전체 대문자는 사용하지 않는다.
  • 기본 라벨은 1~3단어, 최대 20자 이내를 권장한다.
  • 아이콘만 사용하는 버튼에는 반드시 aria-label을 제공한다.
  • 아이콘은 의미를 보조할 때만 사용하며, 텍스트보다 크게 만들지 않는다.
  • 삭제, 결제, 전송처럼 결과가 중요한 작업은 명확한 동사를 사용한다.

7. Accessibility

ARIA attributes

  • 일반 버튼은 native <button>을 사용하므로 별도의 role="button"을 추가하지 않는다.
  • 아이콘 전용 버튼은 aria-label을 필수로 제공한다.
  • 로딩 중에는 aria-busy="true"를 제공한다.
  • 오류 상태인 경우 aria-invalid="true"를 제공할 수 있다.
  • 버튼이 특정 영역을 열거나 닫으면 aria-expanded 및 aria-controls를 사용한다.
  • disabled 상태는 native disabled 속성을 우선 사용한다.

Keyboard interaction

  • Tab: 버튼으로 이동
  • Enter 또는 Space: 버튼 실행
  • Shift + Tab: 이전 포커스 가능 요소로 이동
  • disabled 버튼은 포커스 및 실행 대상에서 제외한다.
  • asChild로 링크를 렌더링하는 경우 링크의 기본 키보드 동작을 유지한다.

Focus management

  • :focus-visible에서만 focus ring을 표시한다.
  • 기본 focus ring은 ring-width-2, ring-color-brand-500, ring-offset-2를 사용한다.
  • 모달 내부 버튼을 클릭한 뒤 모달이 닫히면 트리거 버튼으로 포커스를 반환한다.
  • 버튼을 클릭해 새 콘텐츠가 표시되는 경우 새 콘텐츠의 첫 번째 의미 있는 요소로 포커스를 이동한다.

Screen reader behavior

  • visible label이 있으면 해당 텍스트를 accessible name으로 사용한다.
  • 아이콘 전용 버튼의 아이콘에 aria-hidden="true"를 설정하고 버튼에 aria-label을 지정한다.
  • 로딩 상태에서도 accessible name은 유지한다. 예: 저장 → 저장 중.
  • 스피너만으로 상태를 전달하지 않는다.

Contrast

  • color-brand-500(#2563EB) + color-white: 약 5.17:1
  • color-brand-600(#1D4ED8) + color-white: 약 6.70:1
  • 일반 텍스트 및 버튼 라벨은 WCAG AA 기준 4.5:1 이상을 충족한다.
  • 큰 텍스트 기준은 3:1 이상을 충족해야 한다.
  • disabled 상태는 WCAG 대비 요구사항의 예외가 될 수 있으나, 상태 구분을 opacity만으로 전달하지 않는다.

8. Code Example

프로젝트의 일반적인 shadcn/ui 구조에서는 @/components/ui/button 경로를 사용한다.

// components/ui/button.tsx
"use client"

import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { Loader2 } from "lucide-react"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  [
    "inline-flex items-center justify-center gap-2 whitespace-nowrap",
    "rounded-[8px] text-center font-semibold",
    "transition-colors duration-150 ease-out",
    "focus-visible:outline-none focus-visible:ring-2",
    "focus-visible:ring-[#2563EB] focus-visible:ring-offset-2",
    "disabled:pointer-events-none disabled:opacity-50",
    "[&_svg]:pointer-events-none [&_svg]:shrink-0",
  ],
  {
    variants: {
      variant: {
        default:
          "bg-[#2563EB] text-white hover:bg-[#1D4ED8] active:bg-[#1D4ED8]",
        outline:
          "border border-[#2563EB] bg-transparent text-[#1D4ED8] hover:bg-[#2563EB] hover:text-white",
        ghost:
          "bg-transparent text-[#1D4ED8] hover:bg-[#2563EB]/10 active:bg-[#2563EB]/15",
        destructive:
          "bg-error-500 text-white hover:bg-error-600 active:bg-error-600",
      },
      size: {
        sm: "h-8 px-3 py-2 text-sm [&_svg]:size-4",
        default: "h-10 px-4 py-2 text-base [&_svg]:size-4",
        lg: "h-12 px-6 py-3 text-lg [&_svg]:size-5",
        icon: "size-10 [&_svg]:size-4",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
    loading?: boolean
  }

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  (
    {
      className,
      variant,
      size,
      asChild = false,
      loading = false,
      disabled,
      children,
      ...props
    },
    ref
  ) => {
    const Comp = asChild ? Slot : "button"

    return (
      <Comp
        ref={ref}
        className={cn(buttonVariants({ variant, size, className }))}
        disabled={disabled || loading}
        aria-busy={loading || undefined}
        {...props}
      >
        {loading && <Loader2 className="size-4 animate-spin" aria-hidden="true" />}
        <span className={loading ? "opacity-80" : undefined}>{children}</span>
      </Comp>
    )
  }
)

Button.displayName = "Button"

export { Button, buttonVariants }

사용 예시

import Link from "next/link"
import { Settings } from "lucide-react"

import { Button } from "@/components/ui/button"

export function ExampleActions() {
  return (
    <div className="flex items-center gap-2">
      <Button>저장</Button>

      <Button variant="outline">취소</Button>

      <Button variant="ghost" size="icon" aria-label="설정 열기">
        <Settings aria-hidden="true" />
      </Button>

      <Button asChild>
        <Link href="/dashboard">대시보드로 이동</Link>
      </Button>
    </div>
  )
}

color-error-500, color-error-600, motion-duration-fast, motion-ease-default가 아직 토큰 시스템에 없다면 프로젝트의 기존 semantic token으로 연결하거나 Phase 2 토큰에 추가한다.

More in this category

Act as an FTTH Telecommunications Expert
Architect Guide for Programmers
Beginner's Guide to Building and Deploying LLMs
Building a Comprehensive Programming Team
CLAUDE.md Assembly