컴포넌트/필드 컴포넌트

Checkbox (체크박스)

VanillaFront 2026. 9. 12. 19:19

Va.Checkbox — 체크박스

가장 흔한 폼 입력 중 하나. VanillaFront의 Checkbox는 표준 <input type="checkbox">을 감싸되, 값의 형태를 다양하게 선택 할 수 있고 (true/false, Y/N, 1/0), 3상 상태(mixed), 라벨 클릭 토글, 키보드(스페이스) 지원을 모두 포함합니다.

  • 클래스: Va.Checkbox  va_component.js:4483
  • short name: checkbox
  • 상속: Va.PureField (Input·Combobox와 형제)
  • isContainer: true
  • 베이스 CSS: va-checkbox


1. 기본 사용

{
    tagName: 'checkbox',
    checkboxLabel: '동의합니다',
    checked: false,
    onChange: 'onAgreeChange'
}
  • 좌측: 체크박스 아이콘
  • 우측: 라벨 (동의합니다)
  • 라벨 클릭도 토글로 동작 (기본)

2. Va.Checkbox의 특징

일반 HTML <input type="checkbox">와 크게 다른 점:

항목HTML 표준Va.Checkbox

값 타입 항상 boolean true/false / Y/N / 1/0 선택 가능
3상 상태 indeterminate 프로퍼티 (시각적으로만) checked: 'mixed' 로 지원
라벨 <label for="..."> 별도 태그 checkboxLabel 옵션 하나로 통합
키보드 브라우저 기본 스페이스로 토글, focus 시각 표시 자동
ARIA 개발자가 붙여야 role="checkbox", aria-checked 자동
아이콘 OS 기본 스타일 커스텀 SVG 아이콘 (테마 반영)

3. 값 타입 3종 — valueType

체크 상태를 어떤 값으로 다룰지 지정합니다.

valueType체크 시미체크 시언제 쓰나

(미지정, 기본) true false 표준 JS boolean
'YN' 'Y' 'N' DB가 Y/N 컬럼일 때
'10' 1 0 DB가 int 0/1 컬럼일 때

예시

// 기본 boolean
{ tagName: 'checkbox', checkboxLabel: '동의', valueType: undefined }
// getChecked() → true / false

// Y/N 문자열
{ tagName: 'checkbox', checkboxLabel: '동의', valueType: 'YN' }
// getChecked() → 'Y' / 'N'

// 0/1 숫자
{ tagName: 'checkbox', checkboxLabel: '동의', valueType: '10' }
// getChecked() → 1 / 0

서버 DB 스키마에 맞추는 게 핵심입니다. Y/N 컬럼인데 boolean으로 다루면 저장 때마다 변환하느라 코드가 지저분해집니다. valueType으로 처음부터 맞춰두세요.


4. 3상 상태 (checked: 'mixed')

일반적인 체크박스는 켜짐/꺼짐 2상이지만, VanillaFront는 중간 상태(mixed) 를 지원합니다.

{
    tagName: 'checkbox',
    checkboxLabel: '전체 선택',
    checked: 'mixed'
}

언제 쓰나:

  • 부모-자식 트리 구조에서 자식 일부만 선택된 상태
  • "모두 선택" 체크박스가 자식 중 일부만 체크됐음을 시각화할 때

시각: 체크 아이콘이 ico_checkbox_indeterminate (가로 막대) 로 표시됩니다.

ARIA: aria-checked="mixed"로 자동 세팅 → 스크린리더가 정확히 인식.

실전 패턴

class TreeCheckbox extends Va.View {
    updateParent() {
        const children = this.getRefs('child');
        const checked = children.filter(c => c.getChecked()).length;

        if (checked === 0)                     this.getRef('parent').setChecked(false);
        else if (checked === children.length)  this.getRef('parent').setChecked(true);
        else                                    this.getRef('parent').setChecked('mixed');
    }
}

5. 주요 속성

체크 상태

속성기본값설명

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

라벨

속성기본값설명

checkboxLabel 우측에 표시되는 라벨 텍스트
checkboxLabelClick true 라벨 클릭으로도 토글 가능 여부

데이터 (그리드·리스트에서 활용)

속성설명

key 데이터 key 필드명 (그리드의 checkbox 컬럼 등에서 사용)
display 표시 필드명

PureField 상속

readonly, disabled, size, appearance, stopPropagation 등 표준.


6. 이벤트

이벤트시그니처발생 시점

change (component, element, checked, evt) 체크 상태 변경 시 — 가장 자주 씀. checked가 새 상태값
click (component, element, evt) 클릭 시 (change와 함께 발생)
keydown (component, element, keyCode, evt) 스페이스 눌러 토글 시
keyup (component, element, keyCode, evt) 키업
focus / blur (component, element, evt) 포커스 진입/이탈

change 콜백 예시

onAgreeChange(comp, el, checked, evt) {
    console.log('새 상태:', checked);   // true / 'Y' / 1 / 'mixed' 등
    this.getRef('submitBtn').setDisabled(!checked);
}

⚠️ change 이벤트의 세 번째 인자가 새 상태값 — 다른 이벤트와 시그니처가 미묘하게 다릅니다. 필요하면 comp.getChecked()로 정규화된 값을 다시 조회.


7. 메서드

상태 조회·변경

메서드설명

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

포커스

메서드설명

focus() fieldWrapperElement에 포커스 (실제 <input>이 아님)
blur() 블러

상태 (PureField 상속)

메서드설명

setDisabled(bool) / setReadOnly(bool) 상태

주의: setValue() / getValue()는 PureField의 것을 쓰지만, 체크박스의 실질 값은 getChecked() / setChecked()로 다루는 게 정석입니다.


8. 내부 구조

<div elname="element" class="va-checkbox [checked|mixed] [focused] [disabled]"
     tag-name="checkbox" field="true">
  <div elname="inner" class="checkbox-inner">
    <div elname="fieldWrapper" class="field-wrapper" tabindex="0"
         role="checkbox" aria-checked="true|false|mixed" aria-label="동의합니다">
      <input elname="field" type="checkbox" style="display:none" tabindex="-1">
      <span elname="icon" class="icon ico_checkbox_checked_fill">☑</span>
    </div>
    <label elname="checkboxLabel" class="label">동의합니다</label>
  </div>
</div>

핵심 트릭:

  • <input type="checkbox">는 display:none — 시각은 아이콘이 담당, 값은 여전히 표준 폼 서브밋에 참여
  • fieldWrapper가 실제 tabindex 대상 — 키보드 포커스가 이쪽으로. <input>은 tabindex="-1"
  • 아이콘 종류 3가지:
    • ico_checkbox_unchecked — 빈 사각형
    • ico_checkbox_checked_fill — 체크된 상태
    • ico_checkbox_indeterminate — mixed 상태 (가로 막대)
  • ARIA 자동  role="checkbox", aria-checked, aria-label (checkboxLabel 있을 때)

9. 접근성 (a11y)

VanillaFront Checkbox는 접근성이 잘 되어 있습니다.

요소값

role "checkbox" (자동)
aria-checked "true" / "false" / "mixed" (자동)
aria-label checkboxLabel 값 (자동)
tabindex 0 (Tab으로 접근 가능)
스페이스 키 토글 (자동 처리)

별도 세팅 없이도 스크린리더 사용자가 정확히 이해합니다.


10. Checkbox 계열 형제 컴포넌트

컴포넌트역할

Va.Checkbox 단일 체크박스 (이 문서)
Va.CheckboxField Checkbox + Field 래퍼 (라벨/검증)
Va.CheckboxGroup 여러 체크박스 그룹 (배열로 선택)
Va.CheckboxGroupField CheckboxGroup + Field 래퍼
Va.CheckboxMixed 3상 상태 전용 컴포넌트 (자식과 연동)

11. 언제 쓰나

Checkbox가 맞을 때

  • 동의 여부 (약관, 마케팅 수신)
  • 필터 on/off (표시 여부, 활성 상태)
  • 다중 선택 목록 (여러 옵션 중 원하는 것들)
  • 그리드의 행 선택 컬럼
  • 부모-자식 트리에서 일괄 선택

다른 걸 쓸 때

  • 라디오형 배타 선택 (하나만) → Va.Radio / Va.RadioGroup
  • 라벨 붙은 폼 필드 → Va.CheckboxField
  • 여러 선택지 그룹 → Va.CheckboxGroup
  • ON/OFF 스위치 UI → Va.Switch (있다면)
  • 시각적으로 버튼 형태로 → Va.ToggleButton

12. 흔한 조합 예시

// 표준 동의
{
    tagName: 'checkbox',
    checkboxLabel: '이용약관에 동의합니다',
    ref: 'agree',
    onChange: 'onAgreeChange'
}

// Y/N (DB 스키마 맞춤)
{
    tagName: 'checkbox',
    checkboxLabel: '수신 동의',
    valueType: 'YN',
    checked: 'N'
}

// 0/1 (int 컬럼)
{
    tagName: 'checkbox',
    checkboxLabel: '활성',
    valueType: '10',
    checked: 1
}

// 라벨 없이 아이콘만
{
    tagName: 'checkbox',
    checked: false,
    style: { width: '32px' }
}

// mixed 상태 (전체 선택)
{
    tagName: 'checkbox',
    checkboxLabel: '전체 선택',
    checked: 'mixed',
    ref: 'selectAll'
}

// 읽기 전용
{
    tagName: 'checkbox',
    checkboxLabel: '완료됨',
    checked: true,
    readonly: true
}

// 라벨 클릭 비활성 (아이콘만 클릭 허용)
{
    tagName: 'checkbox',
    checkboxLabel: '주의: 신중히 선택',
    checkboxLabelClick: false
}

13. 실전 패턴 — 전체 선택 + 개별 선택

class MultiSelect extends Va.View {
    onSelectAll(comp, el, checked, evt) {
        // 전체 선택 체크 시 모든 자식 체크
        this.getRefs('child').forEach(c => c.setChecked(checked));
    }

    onChildChange(comp, el, checked, evt) {
        // 자식 상태 → 부모 mixed 계산
        const children = this.getRefs('child');
        const count = children.filter(c => c.getChecked()).length;

        if (count === 0)                    this.getRef('parent').setChecked(false);
        else if (count === children.length) this.getRef('parent').setChecked(true);
        else                                 this.getRef('parent').setChecked('mixed');
    }

    config() {
        return {
            tagName: 'div',
            layout: 'ds-flex fd-column gap-s',
            tags: [
                {
                    tagName: 'checkbox',
                    ref: 'parent',
                    checkboxLabel: '전체 선택',
                    onChange: 'onSelectAll'
                },
                {
                    tagName: 'div',
                    layout: 'ds-flex fd-column gap-xs',
                    style: { paddingLeft: '24px' },
                    tags: [
                        { tagName: 'checkbox', ref: 'child', checkboxLabel: '항목 1', onChange: 'onChildChange' },
                        { tagName: 'checkbox', ref: 'child', checkboxLabel: '항목 2', onChange: 'onChildChange' },
                        { tagName: 'checkbox', ref: 'child', checkboxLabel: '항목 3', onChange: 'onChildChange' }
                    ]
                }
            ]
        };
    }
}

getRefs('child')가 배열을 반환하므로 forEach로 조작 가능. mixed 상태를 자동 계산하는 표준 패턴입니다.


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

  1. checked는 다양한 형태 수용  true, 'true', 'Y', 'y', 1, '1' 모두 체크로 인식. 'mixed'는 별도.
  2. getChecked()는 valueType 규약에 맞춰 반환 — 필드 세팅과 조회 형태를 일관되게 유지.
  3. change 이벤트 인자에 새 상태값 포함  (comp, el, checked, evt). 다른 이벤트보다 인자 많음.
  4. click과 change 둘 다 발생 — 같은 클릭에 두 이벤트가 함께. 콜백에 로직 넣을 때 중복 실행 조심.
  5. <input> 자체는 숨겨짐 — 시각은 아이콘. 폼 서브밋에는 참여.
  6. fieldWrapper가 실제 focus 대상  focus()가 <input>이 아니라 wrapper에 포커스.
  7. 스페이스 키 자동 토글 — keydown 32번 처리. preventDefault 자동.
  8. checkboxLabel 없으면 aria-label도 없음 — 접근성 관점에서 라벨 지정 권장.
  9. checkboxLabelClick: false 옵션 — 라벨 무심코 클릭하는 UX가 문제되는 상황(예: 긴 약관 텍스트)에 유용.
  10. selected 속성은 별개 — checked와 다른 개념. 그리드·리스트 항목의 선택 상태 등에서 활용.
  11. focus 이벤트가 readonly/disabled 상태에서 안 발생 — 소스에 조기 return 있음.
  12. mixed 상태에서 클릭 시 — 코드상 boolean 분기라 mixed → true 로 넘어감. 필요하면 별도 처리.
  13. 라벨 클릭 시 내부적으로 wrapper에 click 재전송  dispatchEvent(new MouseEvent('click')) 방식. 이벤트가 두 번 처리될 위험은 없음.
  14. 초기값 세팅 시 setChecked 권장 — 프로그래매틱 변경엔 setChecked 사용. 옵션에 직접 세팅해도 되지만 setter가 update까지 트리거해 안전.

15. checkbox vs radio vs switch 선택

상황추천

ON/OFF 단일 (동의, 활성) checkbox
여러 옵션 중 여러 개 선택 checkbox × N (또는 checkboxGroup)
여러 옵션 중 하나만 선택 radio × N (또는 radioGroup)
ON/OFF를 스위치 스타일 (설정 화면) switch
시각적으로 버튼처럼 (툴바 토글) toggleButton
부모-자식 트리에서 일괄 선택 checkbox + mixed 상태

"여러 선택 가능이면 checkbox, 하나만 가능이면 radio" 가 기본 원칙입니다.

'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글

CheckboxGroup (체크박스그룹)  (0) 2026.09.12
CheckboxField (체크박스필드)  (0) 2026.09.12
TimeField (시각필드)  (0) 2026.09.12
TimePicker (시각선택)  (0) 2026.09.12
MonthField (년월필드)  (0) 2026.09.12