디자인 토큰과 컴포넌트·폼 규칙을 사용해 React 앱에서 일관된 UI를 만드는 법을 배우고, AI가 생성한 화면의 간격·타이포·폼 동작을 맞추세요.

UI 불일치는 클릭하면서 느껴지는 사소한 디테일에서 보입니다. 어떤 페이지는 여유 있는 패딩을 쓰고, 다른 페이지는 꽉 끼어 보입니다. 제목 크기가 들쭉날쭉하고, 버튼 모양과 색이 바뀌며, 같은 입력이 화면에 따라 다르게 동작합니다.
대부분의 경우 이런 변화는 몇 가지 기본 항목에서 옵니다:
이건 별개의 프롬프트로 화면을 생성할 때 흔히 생깁니다. 각 프롬프트는 사실상 새로 시작하므로 모델은 빠진 결정을 추측해서 채웁니다. “모던한 스타일 사용”이라고 해도 8px 대 12px 갭, 14px 대 16px 본문, 언제 에러를 보여줄지, 기본 버튼이 어떻게 보이는지 같은 수백 가지 작은 선택이 남습니다.
두세 페이지를 수동으로 정리할 수는 있지만, 이렇게 하면 확장되지 않습니다. 일회성 CSS 수정을 쫓아다니고, 스타일을 파일 간에 복사하고, 폼을 다시 고치느라 시간을 쓰게 됩니다. 규칙은 프로젝트에 있는 게 아니라 귀하의 머릿속에만 있는 셈입니다.
오늘 로그인 화면을 생성하고 내일 프로필 화면을 생성한다고 상상해 보세요. 한 화면은 제출할 때만 에러를 보여주고 다른 화면은 블러 시점에 에러를 보여주면 사용자가 눈치챕니다. 기본 버튼 높이가 화면마다 달라지면 앱은 이어 붙인 것처럼 느껴집니다.
모든 화면이 동일한 공유 시스템을 따를 때 일관성이 기본값이 됩니다: 디자인 토큰(간격, 글꼴, 색상)과 소규모 컴포넌트 및 폼 규칙들입니다.
디자인 토큰은 UI 전반에서 재사용하는 간단한 이름 값입니다. 매번 “편한 패딩”을 요청하는 대신 space-4 같은 토큰을 사용하세요. “약간 둥글게” 대신 radius-md를 사용합니다. 매핑 값이 나중에 바뀌어도 이름은 고정됩니다.
토큰은 모든 화면이 공유하길 원하는 결정들의 집합입니다. 추측과 취향을 제거해 주며, 이것이 바로 화면을 생성하거나 새로운 페이지를 만들 때 드리프트를 유발하는 원인입니다.
일반적인 토큰은 간격, 타이포그래피, 색상, 형태, 그리고 소량의 엘리베이션을 포함합니다. 실용적인 이점은 명확합니다: 헤더는 항상 같은 크기를 쓰고, 카드는 항상 같은 패딩을 쓰며, 기본 버튼은 같은 색과 반경을 유지합니다.
제품 전체의 전체적인 느낌에 영향을 주는 것들을 토큰화하세요: 간격 스케일, 글꼴 크기와 행간, 핵심 색상(텍스트, 배경, 기본, 위험, 테두리), 소수의 테두리 반경.
콘텐츠에 따라 달라지는 선택들은 유연하게 두세요. 예를 들어 카피 길이, 어떤 아이콘을 쓸지, 섹션에 카드가 두 개 필요한지 세 개 필요한지 같은 것들입니다.
화면을 생성할 때(예: Koder.ai 같은 도구 포함) 처음에 작은 토큰 세트를 제공하면 추측이 줄어들고 출력 결과가 눈에 띄게 일관됩니다.
토큰 세트는 허용된 값들의 짧은 메뉴일 뿐입니다. 작을수록 좋습니다. 무작위 선택의 여지가 줄어들지만 화면을 어긋나게 만드는 기본은 커버해야 합니다.
간격부터 시작하세요. 하나의 스케일을 정하고 패딩, 갭, 레이아웃 전반에 사용하세요. 예: 4, 8, 12, 16, 24, 32은 대부분의 UI에 적합합니다. 디자인에서 10px이나 18px을 요구하면 새로운 숫자를 도입하지 말고 가장 가까운 토큰으로 반올림하세요.
그다음 타이포그래피 기본값을 정의해 제목과 본문이 들쭉날쭉해지지 않게 하세요. 거대한 타입 시스템이 필요하지 않습니다. 반복 가능하고 명확한 단계가 필요합니다.
간결하면서도 실용적인 세트 예시:
접근성도 시스템에 포함되어야 합니다. 포커스 외곽선 스타일(색상, 두께, 오프셋)을 정의해 키보드 사용자가 일관된 포커스 상태를 보게 하세요. 모바일의 최소 탭 타깃(예: 44x44)을 설정하세요. 대비가 예측 가능하도록 텍스트 색상을 소수의 신뢰된 집합으로 제한하세요.
버튼이 때때로 비좁아 보인다면, 어떤 화면은 패딩 10을 쓰고 다른 화면은 12를 써서 그럴 가능성이 큽니다. 토큰이 있으면 이렇게 지정할 수 있습니다: “버튼은 paddingY=8, paddingX=16, radius=12, 포커스 외곽선 토큰, 최소 높이 44.” 값들이 고정되면 생성기는 더 이상 즉흥적으로 꾸미지 않습니다.
토큰은 숫자를 정합니다. 컴포넌트 규칙은 습관을 정합니다.
작고 핵심적인 컴포넌트 집합을 골라 이것을 화면의 유일한 빌딩 블록으로 취급하세요. 단순하고 재사용 가능하게 유지하세요: Button, Input, Select, Checkbox, Card. TextArea와 Modal을 추가할 수 있지만 동일한 시스템(레이블, 간격, 상태)을 따라야 합니다.
다음으로 변형을 제한하고 언제 허용되는지 정의하세요. 예: Button은 primary, secondary, danger가 있다. Primary는 화면의 주요 액션(보통 하나)에 사용합니다. Secondary는 취소나 낮은 우선순위 액션에 씁니다. Danger는 삭제 같은 파괴적 행동에만 사용합니다. 변형을 정당화할 수 없으면 기본으로 secondary를 사용하세요.
간격 규칙은 미세한 드리프트를 방지합니다. 컴포넌트 내부의 기본값을 정의하세요: Button 패딩, Input 높이, 레이블과 필드 간 갭, 쌓인 필드 사이의 표준 갭. 레이아웃 규칙도 몇 가지 추가하세요: Card는 내부 패딩이 고정되고 헤더/본문 간격이 일관되어야 합니다; Modal은 동일한 너비 단계와 푸터 정렬을 사용합니다.
마지막으로 상태를 협상 불가 항목으로 만드세요. UI가 무작위처럼 보이기 시작하는 곳이 바로 상태입니다:
“프로젝트 생성”처럼 폼이 많은 화면을 생성할 때 이러한 규칙은 혼합된 버튼 크기, 레이블 위치의 이동, 또는 한 페이지에만 나타나는 일회성 ‘특별’ 카드를 방지합니다.
시각이 안정적이어도 많은 “이상하게 느껴짐” 불만은 폼 동작에서 옵니다. 각 화면이 레이블, 에러, 포커스를 다르게 처리하면 사용자는 불일치로 느낍니다.
하나의 폼 패턴을 골라 모든 곳에 사용하세요: 레이블, 선택적/필수 표기, 도움말 텍스트, 그다음 에러 텍스트 순서. 문구도 일관되게 유지하세요(예: 문장형 레이블, 짧은 도움말, 동사로 시작하는 에러 메시지).
대부분의 드리프트를 막는 규칙:
크기와 레이아웃을 고정해 화면들이 다르게 ‘숨쉬지’ 않게 하세요. 입력 하나의 높이, 버튼 하나의 높이, 기본 필드 너비를 정의하세요. 데스크톱에서는 필드를 일관된 그리드에 맞추고 레이블을 입력 위에 쌓으세요. 모바일에서는 필드를 전체 너비로 만들고 불필요한 2열 폼은 피하세요.
간단한 예: “프로젝트 생성” 화면에 Name, Region, Description이 있다고 합시다. Region이 셀렉트여도 다른 필드와 동일하게 취급하세요: 같은 높이, 같은 레이블 위치, 같은 에러 라인. 사용자가 Name을 비워서 제출하면 포커스가 Name으로 이동하고 에러가 아래에 표시되며 레이아웃은 안정적으로 유지됩니다.
Koder.ai에서 화면을 생성한다면 이러한 폼 규칙을 프롬프트에 한 번 넣고 기능별로 재사용하세요. 그러면 모든 새 폼이 반복적인 정리 없이 동일하게 동작합니다.
프롬프트를 작은 UI 계약처럼 다루세요. 간단하고 구체적이며 재사용 가능하게 유지해 각 새 화면이 동일한 간격, 타이포그래피, 컴포넌트, 동작에 맞춰지게 하세요.
실용적인 패턴은 요청 상단에 간결한 UI 명세를 붙이고 그 아래에 화면을 평이한 언어로 설명하는 것입니다.
UI SPEC (apply to every screen)
Tokens:
- Spacing: 4, 8, 12, 16, 24, 32
- Radius: 8
- Typography: H1 24/32, H2 18/26, Body 14/20
- Colors: text, muted, bg, primary, danger (no custom hex)
Components (must use): PageShell, Section, Card, Button, Input, Select, TextArea, FormRow, HelperText, Toast
Layout rules:
- Page padding: 24 desktop, 16 mobile
- Section spacing: 24
- Card padding: 16
- Grid: 12 cols desktop, 4 cols mobile, gap 16
Do:
- Reuse components and tokens only
- Keep labels above inputs, helper text below
Do not:
- Invent new spacing values, font sizes, or one-off CSS
- Mix different button heights or input styles
If a new component is needed:
- Extend an existing component pattern and document it in the output
- Do not create new visual styles outside tokens
명세 다음에는 드리프트를 조기에 잡는 수락 체크를 몇 개 추가하세요:
채팅 기반 생성기를 사용한다면 이 명세를 모든 요청에서 안정적으로 유지하세요. 매번 바꾸면 효과가 없습니다.
아무것도 생성하기 전에 UI 계약을 작성하세요: 작은 토큰 세트(간격, 타입, 색상, 반경, 그림자)와 짧은 컴포넌트 목록(Button, Input, Select, Card, Modal, Table, Toast). 토큰이나 컴포넌트가 빠지면 모델이 새로 만들어 버리고 UI가 드리프트합니다.
그다음 규칙을 시험하는 레퍼런스 화면 하나를 만드세요. 폼이 많은 페이지가 스트레스 테스트로 좋습니다. 헤더, 도움말 텍스트, 검증 에러, 기본/보조 버튼, 성공 토스트 등 여러 요소를 포함하니까요. 그 화면을 기준선으로 취급하세요.
그다음에는 이미 정의한 것을 조합해 새 화면을 만드세요. “새로운 스타일”을 요청하지 말고 같은 Card, 같은 간격 스케일, 같은 타이포그래피 단계, 같은 필드 패턴을 요청하세요.
간단한 워크플로:
“사용자 검색” 화면의 간격이 참조보다 좁다면 한 번에 마진을 패치하지 마세요. 스페이싱 토큰이나 Card 패딩 규칙을 업데이트한 뒤 재생성하세요.
Koder.ai에서는 스냅샷과 롤백이 도움이 됩니다: 기준선을 잠그고 안전하게 실험한 뒤 변경이 드리프트를 유발하면 빠르게 되돌리세요.
토큰과 규칙을 제안 정도로 취급하면 일관성을 잃는 가장 빠른 방법입니다. 작은 예외가 새 화면 전반에 곱절로 늘어납니다.
자주 빠지는 함정 중 하나는 진행 중에 간격 스케일을 바꾸는 것입니다. 초기 화면은 8, 16, 24를 썼는데 새로운 화면이 10과 18을 도입하면(“더 보기 좋다”라는 이유로) 이제 드리프트가 허용되고 기존 화면은 업데이트되지 않습니다.
또 다른 드리프트 원인은 생성기가 새로운 컴포넌트 스타일을 만들도록 내버려 두는 것입니다. “이 버튼 변형만 존재한다”라고 명시하지 않으면 모델이 한 화면에서 다른 반경이나 입력 패딩을 만들어 냅니다.
상태도 자주 놓치는 부분입니다. 로딩, 빈, 에러 상태는 종종 간격과 동작을 바꿉니다. 상태를 나중에 덧붙이면 보통 다른 패턴과 맞지 않습니다.
또한 ‘모던한 부드러운 그림자’처럼 모호한 지시는 피하세요. “에러는 필드 아래에 표시”, “비활성 버튼도 포커스 스타일 유지”, “Enter는 마지막 필드에서만 제출” 같은 구체적이고 반복 가능한 규칙이 중요합니다.
간단한 가드레일 블록을 프롬프트에 붙여넣고 싶다면 짧게 유지하세요:
생성된 화면을 병합하기 전에 2분 정도만 스캔하세요.
간격부터 시작하세요. 13px 같은 임의 값이나 ‘맞추기 위해 추가한’ 일회성 마진을 찾아보세요. 토큰을 쓴다면 모든 갭은 승인된 집합에서 나와야 합니다(거터, 카드 패딩, 폼 필드 사이 간격 포함).
그다음 타이포그래피를 타입 스케일과 비교하세요. 제목은 예측 가능하게 단계적으로 내려가야 합니다. 본문 텍스트가 비슷한 섹션 사이에서 크기가 바뀌면 안 됩니다. 행간도 중요합니다, 특히 설정 페이지처럼 정보가 밀집된 화면에서요.
버튼도 살펴보세요. 변형과 크기는 규칙을 따라야 합니다: 주요 액션엔 primary, 덜 중요한 액션엔 secondary, 삭제엔 danger. 버튼 높이, 아이콘 위치, 라벨 스타일이 일치해야 합니다.
폼은 구조가 대부분입니다. 레이블 위치는 한 곳에 있어야 하고, 필수 표기는 한 규칙을 따르며, 도움말과 에러가 경쟁하지 않고 일관된 위치에 나타나야 합니다.
짧은 체크리스트:
마지막으로 모바일도 빠르게 확인하세요. 너비를 줄여 레이아웃이 새로운 글꼴 크기나 간격을 임의로 도입하지 않고 적응하는지 확인하세요.
간단한 온보딩 플로우를 생각해 보세요: 세 화면(Profile, Preferences, Confirm)과 나중의 Settings 페이지. 각 화면이 별도로 생성되더라도 동일한 디자이너가 만든 것처럼 느끼게 하고 싶습니다.
무엇을 생성하기 전에 작은 토큰 세트와 몇 가지 컴포넌트 규칙을 제공합니다:
TOKENS
- spacing: xs=4, sm=8, md=12, lg=16, xl=24
- radius: sm=8, md=12
- type: body=14/20, title=20/28, label=12/16
- layout: pageMax=960, sectionGap=24, fieldGap=12
COMPONENT RULES
- Page: max width=pageMax, padding=xl, sectionGap between blocks
- Card: padding=lg, radius=md
- Field: label above, helper below, fieldGap between fields
- Button row: primary on right, gap=sm
- Errors: shown under field, same copy style, no alerts
이제 “Profile”과 “Preferences”를 별개로 생성하세요. 두 화면 모두 Page, Card, Field, Button row를 사용하도록 되어 있으니 동일한 여백, 레이블 간격, 버튼 배치로 생성됩니다. Confirm 단계는 읽기 전용 텍스트가 많아도 여전히 맞춰집니다.
폼 동작은 드리프트가 자주 숨어드는 곳이므로 한 번 정의하고 재사용하세요: 유효하지 않으면 제출 버튼 비활성, 블러나 제출 후 인라인 에러만 표시, Enter는 마지막 단계에서만 제출, Back 버튼은 이미 입력한 값을 지우지 않음.
새 UI 조각이 필요하면 모델이 즉흥으로 만들지 마세요. 규칙 하나를 추가한 뒤 재생성하면서 재사용을 염두에 두세요:
토큰과 규칙을 실제로 사용하는 재사용 가능한 명세로 만드세요. 붙여넣기하기에 너무 길면 지켜지지 않습니다.
실용적 명세에는 보통: 토큰 표(간격, 타입, 반경, 색상), 짧은 컴포넌트 규칙 세트(버튼, 입력, 카드, 제목), 폼 동작 규칙(검증 타이밍, 에러, 비활성/로딩), 레이아웃 기본값(페이지 패딩, 최대 너비, 섹션 간격), 그리고 짧은 “하지 말 것” 목록(임의 마진, 일회성 글꼴 크기)이 포함됩니다.
그다음 습관 하나: 개별 픽셀을 먼저 바꾸지 말고 명세를 업데이트하세요.
Koder.ai (koder.ai)를 사용하는 경우, planning mode에서 명세를 재진술하고 확인하기 좋습니다. 대안을 시험하고 싶다면 snapshots와 rollback으로 안정된 기준선을 잃지 않고 탐색할 수 있습니다.
각 화면 요청이 새로 시작되기 때문에 그렇습니다. 공유된 시스템을 제공하지 않으면 생성기가 누락된 세부 항목(간격, 글꼴 크기, 버튼 패딩, 그림자, 폼 동작 등)을 추측으로 채웁니다. 그 결과 작은 차이들이 페이지 전반에 쌓입니다.
디자인 토큰은 간격, 글꼴 크기, 색상, 반경처럼 재사용 가능한 이름 있는 값입니다.
“편한 패딩” 대신 space-md 같은 토큰을 사용하세요. 이름이 고정되어 있으니 모든 화면이 같은 결정을 재사용해 UI가 흐트러지는 것을 막습니다.
눈에 띄는 드리프트를 유발하는 항목만 작게 시작하세요:
새 값을 써야 한다면 10px이나 18px처럼 임의 숫자를 만들지 말고 가장 가까운 토큰으로 반올림하세요.
모든 요청 상단에 작은 UI 명세 블록을 붙여 계약처럼 다루세요:
그 아래에 화면을 설명하세요. 핵심은 명세를 화면마다 변경하지 않고 유지하는 것입니다.
토큰은 수치 값을 정의하고, 컴포넌트 규칙은 습관을 정합니다. 유용한 규칙 예시:
변형을 정당화할 수 없다면 기본으로 되돌리세요.
하나의 패턴을 골라 모든 곳에 적용하세요:
이렇게 하면 어떤 화면은 블러에서 검증하고 다른 화면은 제출에서만 검증하는 식의 불일치가 사라집니다.
몇 가지 필수 상태 규칙을 정의하세요:
상태를 지정하지 않으면 각 화면이 저마다의 패턴을 만들어 냅니다.
스타일을 즉흥적으로 만들지 마세요. 다음과 같이 기존 패턴을 문서화된 확장으로 추가하세요:
토큰으로 설명할 수 없다면 너무 커스텀한 경우일 가능성이 높아 드리프트를 유발합니다.
시스템을 시험하는 ‘레퍼런스’ 화면(폼이 많은 페이지 권장)을 하나 만든 뒤 모든 새 화면에 같은 명세를 재사용하세요.
Koder.ai에서는 planning mode에서 명세를 재확인하고, snapshots and rollback으로 안정된 기준선을 유지하며 실험할 수 있습니다.
병합하기 전에 간단히 점검하세요:
문제가 있으면 개별 마진을 패치하지 말고 명세/토큰을 업데이트한 뒤 재생성하세요.