컴포넌트/필드 컴포넌트

CheckboxField (체크박스필드)

VanillaFront 2026. 9. 12. 19:23

Va.CheckboxField — 라벨(폼) + 체크박스 필드

Va.Checkbox가 순수 체크박스라면, Va.CheckboxField는 그 위에 폼 라벨·필수 표시·검증 메시지를 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.Checkbox를 소유하는 Composition 구조.

  • 클래스: Va.CheckboxField  va_component.js:10202
  • short name: checkboxField
  • 상속: Va.Field (다른 Field 형제들과 같음)
  • 내부 컴포넌트: Va.Checkbox 인스턴스 (fieldComponent)
  • isContainer: true
  • 베이스 CSS: va-field


1. 기본 사용

{
    tagName: 'checkboxField',
    label: '수신 동의',
    checkboxLabel: '이메일 수신에 동의합니다',
    checked: false,
    required: true,
    onChange: 'onAgreeChange'
}

두 종류의 라벨이 있는 게 핵심 포인트:

  • label — Field가 담당하는 폼 라벨 (상단 또는 좌측)
  • checkboxLabel — Checkbox가 담당하는 체크 옆 텍스트

2. Checkbox / 다른 Field와의 차이

항목Va.CheckboxVa.CheckboxFieldVa.InputField

폼 라벨(label)
체크 옆 텍스트(checkboxLabel)
검증 메시지
info 툴팁
필수 표시 ✓ (별표)
3상 상태(mixed)
valueType (YN/10/boolean)

한 줄 요약: "폼 안 라벨 붙은 체크박스."


3. 두 라벨의 관계

가장 헷갈리기 쉬운 지점이라 그림으로:

┌─────────────────────────────────────────┐
│ 수신 동의 *                              │  ← label (폼 라벨, Field 담당)
│                                          │
│  ☑  이메일 수신에 동의합니다             │  ← checkboxLabel (Checkbox 담당)
│                                          │
│ [ 검증 메시지 자리 ]                     │  ← Field가 자동 관리
└─────────────────────────────────────────┘

라벨 형태 선택 가이드

상황추천

폼 관행 준수 (좌측 라벨, 우측 필드 정렬) 두 라벨 다 사용
약관 동의류 (한 줄로 자연스럽게) checkboxLabel만
필수 표시 별표 필요 label에 required: true
폼 없이 그냥 인라인 Va.Checkbox 직접

4. 주요 속성

체크 상태 (Checkbox 계승)

속성기본값설명

checked false 상태값. true/false, 'Y'/'N', 1/0, 'mixed' 모두 인식
valueType undefined 'YN' / '10' / 미지정 (표준 boolean)
selected 선택 상태 (checked와 별개)

두 라벨

속성설명

label 폼 라벨 (Field 상속)
checkboxLabel 체크 옆 텍스트 (Checkbox 옵션)
checkboxLabelClick 체크 옆 텍스트 클릭으로 토글 여부 (기본 true)

데이터 매핑

속성설명

key / display 그리드·리스트 활용 시 데이터 필드명

라벨 관련 (Field 상속)

속성설명

labelPosition top / bottom / left / right
labelWidth 라벨 폭
noLabel 폼 라벨 숨김 (체크박스 옆 텍스트는 유지)
infoButton info 아이콘
required 필수 표시

검증

속성설명

validation {state, size, message}
validationState success / warning / error
validationMessage 메시지

세부 커스터마이즈 (checkbox 옵션 키)

{
    tagName: 'checkboxField',
    label: '동의',
    checkbox: {                    // ← 내부 Checkbox에 직접 전달
        checkboxLabelClick: false
    }
}

각 Field 계열 옵션 키:

  • InputField → input
  • ComboboxField → combobox
  • CheckboxField → checkbox
  • DateField → datePicker
  • TimeField → timePicker

5. 이벤트

Checkbox의 이벤트를 재발화 + Field 표준:

이벤트시그니처발생 시점

change (component, element, checked, evt) 체크 상태 변경 시. checked가 새 상태값
click (component, element, evt) 클릭 시
keydown (component, element, keyCode, evt) 스페이스 눌러 토글 시. 검증 자동 리셋
keyup (component, element, keyCode, evt) 키업
focus / blur (component, element, evt) 포커스 진입/이탈
select (component, element, evt) 선택 이벤트 (있으면 검증 자동 리셋)

change 콜백 예시

onAgreeChange(comp, el, checked, evt) {
    console.log('새 상태:', checked);
    if (checked) {
        this.getRef('submitBtn').setDisabled(false);
    }
}

checked 값이 valueType 규약을 따르지 않은 원시 값일 수 있으니, 정확한 값이 필요하면 comp.getChecked()로 재조회하세요.

⚠️ 주의: 이벤트 리스너 등록 코드가 va_component.js:10245-10295에서 여러 개인데, 특정 이벤트가 중복 dispatch될 위험도 있어요. 콜백에 부작용 로직 넣을 때 조심.


6. 메서드

상태 조회·변경

메서드설명

getChecked() 현재 값 반환. valueType 규약에 맞춰 반환
setChecked(value) 상태 세팅. 다양한 형태 수용 (true/'Y'/1/'mixed')
check() true로 세팅 (편의)
uncheck() false로 세팅 (편의)

상태 (Field 상속)

메서드설명

setDisabled(bool) / getDisabled() 비활성화
setReadOnly(bool) / setReadonly(bool) 읽기 전용
setLabel(label) 폼 라벨 변경
setSize(size) 크기

검증

메서드설명

setValidation(state, message) 검증 표시 + aria
clearValidation() 검증 해제

포커스

메서드설명

focus() / blur() 내부 Checkbox에 위임

⚠️ getChecked()의 valueType 처리에서 미묘한 차이:

서버 전송·비교 시 이 차이가 문제될 수 있으니 팀 안에서 통일해서 쓰세요.


7. 내부 구조

<div elname="element" class="va-field [vertical|horizontal]" field="true">
  <div elname="inner" class="field-inner">
    <div elname="labelDiv" class="label-div">
      <label cpname="label">수신 동의 <span class="required">*</span></label>
    </div>
    <div elname="comment" class="field-comment"></div>
    <div elname="fieldDiv" class="field-div">
      <div cpname="field" class="va-checkbox [checked]">      ← 내부 Va.Checkbox
        <div class="checkbox-inner">
          <div class="field-wrapper" tabindex="0"
               role="checkbox" aria-checked="true" aria-label="이메일 수신...">
            <input type="checkbox" style="display:none">
            <span class="icon ico_checkbox_checked_fill">☑</span>
          </div>
          <label class="label">이메일 수신에 동의합니다</label>   ← checkboxLabel
        </div>
      </div>
    </div>
  </div>
  <div elname="validationDiv" style="display:none">
    <div class="va-validation">...</div>
  </div>
</div>

핵심: Checkbox 자체의 구조를 그대로 유지하면서, 바깥에 Field가 폼 라벨·검증 영역을 감쌈.


8. 언제 쓰나

CheckboxField가 맞을 때

  • 폼 안 동의 항목 (약관 동의, 마케팅 수신)
  • 필수 체크가 필요한 항목 (required: true + 검증)
  • 폼 정렬 (다른 필드들과 라벨 위치·폭 통일)
  • info 툴팁 필요 (약관 설명 링크 등)

다른 걸 쓸 때

  • 라벨 없이 인라인 → Va.Checkbox
  • 여러 옵션 중 여러 개 선택 → Va.CheckboxGroupField
  • 여러 옵션 중 하나만 → Va.RadioField / Va.RadioGroupField
  • ON/OFF 스위치 UI → Va.Switch
  • 3상 전용 (부모-자식 연동) → Va.CheckboxMixed

9. 흔한 조합 예시

// 표준 동의
{
    tagName: 'checkboxField',
    label: '약관 동의',
    checkboxLabel: '이용약관에 동의합니다',
    required: true,
    onChange: 'onAgreeChange'
}

// DB 스키마에 맞춰 Y/N
{
    tagName: 'checkboxField',
    label: '수신 여부',
    checkboxLabel: '마케팅 정보 수신 동의',
    valueType: 'YN',
    checked: 'N'
}

// 0/1 (int 컬럼)
{
    tagName: 'checkboxField',
    label: '상태',
    checkboxLabel: '활성화',
    valueType: '10',
    checked: 1
}

// 좌측 라벨 (폼 정렬)
{
    tagName: 'checkboxField',
    label: '알림',
    labelPosition: 'left',
    labelWidth: 100,
    checkboxLabel: '이메일 알림 받기',
    checked: true
}

// 폼 라벨 없이 (checkbox만)
{
    tagName: 'checkboxField',
    noLabel: true,
    checkboxLabel: '한 줄 표시로 충분',
    checked: false
}

// info 툴팁
{
    tagName: 'checkboxField',
    label: '개인정보 동의',
    checkboxLabel: '개인정보 처리방침에 동의합니다',
    infoButton: {
        tooltip: '자세한 내용은 이용약관 페이지 참조'
    },
    required: true
}

// 검증
{
    tagName: 'checkboxField',
    label: '필수 동의',
    checkboxLabel: '동의',
    ref: 'agree',
    required: true,
    onChange: 'onAgreeChange'
}

10. 실전 예 — 회원가입 약관 동의 (다중)

class Signup extends Va.View {
    onSubmit(btn, el, evt) {
        // 필수 약관 검증
        if (!this.getRef('agreeTerms').getChecked()) {
            this.getRef('agreeTerms').setValidation('error', '이용약관 동의는 필수입니다');
            return;
        }
        if (!this.getRef('agreePrivacy').getChecked()) {
            this.getRef('agreePrivacy').setValidation('error', '개인정보 처리방침 동의는 필수입니다');
            return;
        }

        // 마케팅 동의는 선택
        const marketing = this.getRef('agreeMarketing').getChecked();

        SignupService.register(this, {
            agreeTerms:     'Y',
            agreePrivacy:   'Y',
            agreeMarketing: marketing ? 'Y' : 'N'
        }, this.onRegistered);
    }

    onRegistered(view, ok, res) {
        if (ok) new Va.Alert({ title: '완료', message: '가입 완료' }).show(view);
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '약관 동의' },
                    {
                        tagName: 'checkboxField',
                        label: '이용약관 [필수]',
                        checkboxLabel: '이용약관 전체에 동의합니다',
                        ref: 'agreeTerms',
                        valueType: 'YN',
                        required: true
                    },
                    {
                        tagName: 'checkboxField',
                        label: '개인정보 [필수]',
                        checkboxLabel: '개인정보 처리방침에 동의합니다',
                        ref: 'agreePrivacy',
                        valueType: 'YN',
                        required: true
                    },
                    {
                        tagName: 'checkboxField',
                        label: '마케팅 [선택]',
                        checkboxLabel: '마케팅 정보 수신에 동의합니다',
                        ref: 'agreeMarketing',
                        valueType: 'YN'
                    },
                    {
                        tagName: 'button',
                        text: '가입 완료',
                        appearance: 'primary',
                        onClick: 'onSubmit'
                    }
                ]
            }]
        };
    }
}

포인트:

  • 각 항목의 필수 여부를 label에 명시
  • valueType: 'YN'로 통일하면 서버 전송이 자연스러움
  • 검증은 setValidation / clearValidation으로 인라인 에러 메시지

11. 알아두면 좋을 주의사항

  1. 두 라벨 개념 혼동 주의  label은 폼 라벨, checkboxLabel은 체크 옆 텍스트.
  2. getChecked() 반환값이 Checkbox와 미묘하게 다름  valueType: '10'일 때 CheckboxField는 문자열 '1'/'0' 반환, Checkbox는 숫자 1/0 반환.
  3. change 이벤트 시그니처가 특별함  (comp, el, checked, evt)로 새 상태값이 직접 전달.
  4. 옵션 키 checkbox — 세부 커스터마이즈용.
  5. 검증 자동 리셋 있음  keydown·select 이벤트 시 이전 에러가 자동으로 사라짐.
  6. noLabel: true로 폼 라벨만 숨기기 — checkboxLabel은 유지됨.
  7. required: true로 별표만 표시 — 실제 미체크 시 검증은 개발자가 setValidation() 호출.
  8. mixed 상태 지원 — 부모-자식 트리에서 활용.
  9. focus()는 내부 Checkbox의 fieldWrapper에 포커스 — 실제 <input>이 아님.
  10. 다른 Field 형제와 라벨 위치 통일  labelPosition: 'left' + labelWidth로 폼 정렬.
  11. checkboxLabelClick: false로 라벨 클릭 무시 가능 — 긴 약관 텍스트 실수 방지.
  12. 키보드 스페이스로 토글 — 마우스 없이도 사용 가능. 접근성 좋음.

12. checkboxField vs checkboxGroupField vs radioField 선택

상황추천

단일 동의 (약관 동의 하나) checkboxField
여러 항목 중 여러 개 선택 checkboxGroupField
여러 항목 중 하나만 radioGroupField
ON/OFF 스위치 UI switchField (있다면)
폼 안이 아닌 인라인 Va.Checkbox 직접
필수 동의 별표 표시 checkboxField + required: true