PatternsP4 본문

Form Field

입력 라벨, 설명, 오류, 폼 레벨 검증 메시지를 같은 방식으로 배선하는 필드/검증 패턴입니다.

마지막 업데이트 2026-07-02

AI / Consumer Implementation Contract#

AI 작업자와 소비 프로젝트는 FormField를 단순 래퍼가 아니라 라벨-컨트롤-메시지 배선 계약으로 취급합니다. 세부 설명보다 patterns/form-field.contract.json@wds/ui-web/testingassertFormFieldPatternCompliance(preset, screen)을 우선합니다.

MUST#

  • 보이는 라벨 — 모든 표준 텍스트 입력은 FormField label을 사용하고, placeholder를 라벨로 대체하지 않습니다.
  • 컨트롤 배선FormField 안의 단일 Input, Textarea, Selectid, aria-describedby, aria-invalid, aria-required가 연결되어야 합니다.
  • 필드 오류 위치 — 특정 필드의 오류는 컨트롤 바로 아래 FormField error로 둡니다.
  • 폼 오류 위치 — 한 필드에 귀속되지 않는 검증 실패는 CTA 바로 위 FormMessage variant="error"로 둡니다.
  • Primary CTA는 하나 — 폼 제출 영역 안의 primary action은 1개만 둡니다.

SHOULD#

  • 라벨, 필드, 설명, 오류는 좌측 정렬을 유지합니다.
  • 도움말은 짧고 실행 가능하게 씁니다.
  • 필수 표시는 장식으로 두고, 실제 필수 상태는 컨트롤의 aria-required로 전달합니다.

NEVER#

  • placeholder-only 입력을 만들지 않습니다.
  • aria-describedby로 연결되지 않은 오류 문구를 표시하지 않습니다.
  • 일반적인 인라인 검증을 Alert, Toast, 페이지 상단 배너로만 처리하지 않습니다.
  • 인증 실패처럼 교차 필드 실패를 특정 필드 오류로 단정하지 않습니다.

프리셋별 구현 계약#

프리셋반드시 있어야 하는 요소절대 없어야 하는 요소
단일 필드FormField, 보이는 라벨, 하나의 Input/Textarea/Select, 선택적 설명placeholder-only 라벨, 분리된 라벨, 연결되지 않은 helper text
필드 오류FormField error, role="alert", 컨트롤 aria-invalid, 오류 id를 참조하는 aria-describedby폼 레벨 오류를 필드 오류로 사용, role="alert" 없는 오류, 연결되지 않은 오류 문구
폼 레벨 오류라벨된 필드들, FormMessage variant="error", primary submit CTA 1개Toast-only 검증, primary CTA 2개 이상, 인증 실패를 필드별 존재 여부 문구로 노출

React 소비 레시피#

import { Button, FormField, FormMessage, Input } from '@wds/ui-web';

export function FormFieldRecipe() {
  return (
    <form>
      <FormField label="이메일" description="회사 메일을 입력하세요.">
        <Input type="email" autoComplete="email" />
      </FormField>
      <Button type="submit">저장</Button>
    </form>
  );
}
import { FormField, Input } from '@wds/ui-web';

export function FieldErrorRecipe() {
  return (
    <FormField label="비밀번호" error="8자 이상이어야 합니다.">
      <Input type="password" autoComplete="current-password" />
    </FormField>
  );
}
import { Button, FormField, FormMessage, Input } from '@wds/ui-web';

export function FormErrorRecipe() {
  return (
    <form>
      <FormField label="이메일">
        <Input type="email" autoComplete="email" />
      </FormField>
      <FormMessage variant="error">입력값을 확인하세요.</FormMessage>
      <Button type="submit">저장</Button>
    </form>
  );
}