RadioField (라디오 필드)
Va.RadioField — 라벨 + 단일 라디오 버튼 필드
Va.Radio가 순수 라디오 버튼이라면, Va.RadioField는 그 위에 폼 라벨·필수 표시·검증 메시지를 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.Radio를 소유하는 Composition 구조. CheckboxField와 완전히 같은 패턴.
- 클래스: Va.RadioField — va_component.js:10356
- short name: radioField
- 상속: Va.Field (다른 Field 형제들과 같음)
- 내부 컴포넌트: Va.Radio 인스턴스 (fieldComponent)
- isContainer: true
- 베이스 CSS: va-field

1. 기본 사용
{
tagName: 'radioField',
label: '결제 방식',
radioLabel: '신용카드',
checked: false,
onChange: 'onPaymentChange'
}
두 종류의 라벨:
- label — Field가 담당하는 폼 라벨 (상단 또는 좌측)
- radioLabel — Radio가 담당하는 라디오 옆 텍스트
2. Radio / 다른 Field와의 차이
항목Va.RadioVa.RadioFieldVa.CheckboxField
| 폼 라벨(label) | ✕ | ✓ | ✓ |
| 라디오 옆 텍스트(radioLabel) | ✓ | ✓ | (checkboxLabel) |
| 검증 메시지 | ✕ | ✓ | ✓ |
| info 툴팁 | ✕ | ✓ | ✓ |
| 필수 표시(별표) | ✕ | ✓ | ✓ |
| 선택 개념 | 배타 (단독은 로직 없음) | 배타 (단독은 로직 없음) | 다중 (단일) |
| valueType | ✓ (반환값만) | ✓ (반환값만) | ✓ |
한 줄 요약: "폼 안 라벨 붙은 단일 라디오. 하지만 대개 실무엔 RadioGroupField가 더 어울림."
⚠️ RadioField 단독 사용의 한계: Radio와 마찬가지로 이 컴포넌트도 배타 로직이 없습니다. 여러 개를 나열해도 서로 자동 해제되지 않아요. 실무에서 배타 선택이 필요하면 Va.RadioGroupField를 사용하세요.
3. 주요 속성
체크 상태 (Radio 계승)
속성기본값설명
| checked | false | 상태값. true/'true'만 정확히 체크 인식 |
| valueType | undefined | 'YN' / '10' / 미지정 (getChecked() 반환값에만 영향) |
| selected | — | 별개 개념 |
두 라벨
속성설명
| label | 폼 라벨 (Field 상속) |
| radioLabel | 라디오 옆 텍스트 (Radio 옵션) |
| radioLabelClick | 라디오 옆 텍스트 클릭으로 선택 가능 (기본 true) |
데이터 매핑
속성설명
| key / display | 그리드·리스트 활용 시 데이터 필드명 |
| direction | 배치 방향 (RadioGroup에서 실질적 활용) |
라벨 관련 (Field 상속)
속성설명
| labelPosition | top / bottom / left / right |
| labelWidth | 라벨 폭 |
| noLabel | 폼 라벨 숨김 |
| infoButton | info 아이콘 |
| required | 필수 표시 |
검증
속성설명
| validation | {state, size, message} |
| validationState | success / warning / error |
| validationMessage | 메시지 |
세부 커스터마이즈 (radio 옵션 키)
{
tagName: 'radioField',
label: '선택',
radio: { // ← 내부 Radio에 직접 전달
radioLabelClick: false
}
}
각 Field 계열 옵션 키:
- InputField → input
- CheckboxField → checkbox
- RadioField → radio
- RadioGroupField → radioGroup
4. 이벤트
Radio의 이벤트를 재발화 + Field 표준:
이벤트시그니처발생 시점
| change | (component, element, checked, evt) | 체크 상태 변경 시. checked가 새 상태값 (항상 true) |
| click | (component, element, evt) | 클릭 시 |
| keydown | (component, element, keyCode, evt) | 키다운. 검증 자동 리셋 (Tab 제외) |
| keyup | (component, element, keyCode, evt) | 키업 |
| focus / blur | (component, element, evt) | 포커스 진입/이탈 |
| select | (component, element, evt) | 선택 이벤트 (검증 자동 리셋) |
⚠️ select 이벤트에 검증 자동 리셋 로직이 있음 — Radio 자체에는 select 이벤트가 정의되어 있지 않지만, RadioField는 select 리스너를 등록하고 있음 (va_component.js:10400). 실질적으론 keydown 리셋만 동작하고 select 리스너는 RadioGroup과 연동될 때를 위한 것으로 보임.
change 콜백 예시
onPaymentChange(comp, el, checked, evt) {
console.log('선택됨:', checked); // 항상 true (Radio는 클릭 시 true로만 바뀜)
// 실질적 값은 어떤 옵션이 선택됐는지에 있으므로
// 여러 개 나열한 경우 comp의 ref로 판단
}
Radio 특유: change의 checked는 사실상 항상 true. 어떤 것이 선택됐는지는 콜백을 받은 컴포넌트로 판단해야 함.
5. 메서드
상태 조회·변경 (Radio 위임 + 로컬 추가)
메서드설명
| getChecked() | 현재 값 반환. valueType 규약에 맞춰 반환 |
| setChecked(value) | 상태 세팅 |
| check() | true로 세팅 (편의) |
| uncheck() | false로 세팅 (편의) |
상태 (Field 상속)
메서드설명
| setDisabled(bool) / getDisabled() | 비활성화 |
| setReadOnly(bool) / setReadonly(bool) | 읽기 전용 |
| setLabel(label) | 폼 라벨 변경 |
| setSize(size) | 크기 |
검증
메서드설명
| setValidation(state, message) | 검증 표시 + aria |
| clearValidation() | 검증 해제 |
포커스
메서드설명
| focus() / blur() | 내부 Radio에 위임 |
⚠️ getChecked()의 valueType: '10' 반환값 주의 — CheckboxField와 같이 문자열 '1'/'0' 반환 (va_component.js:10490, 10492). Radio 원본은 '1'/'0' (문자열). 두 클래스가 통일되어 있어 CheckboxField가 특이한 상황이었다면, 여기선 Radio와도 일치.
6. 내부 구조
<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-radio [checked]"> ← 내부 Va.Radio
<div class="radio-inner">
<div class="field-wrapper" tabindex="0"
role="radio" aria-checked="false" aria-label="신용카드">
<input type="radio" style="display:none">
<span class="icon ico_radio_button_unchecked">◯</span>
</div>
<label class="label">신용카드</label> ← radioLabel
</div>
</div>
</div>
</div>
<div elname="validationDiv" style="display:none">
<div class="va-validation">...</div>
</div>
</div>
두 라벨:
- 상단(또는 좌측)의 폼 라벨 label — Field 담당
- 라디오 우측의 radioLabel — Radio 담당
CheckboxField와 완전히 같은 구조 패턴입니다.
7. 왜 RadioField 단독 사용은 드물까
Radio 자체가 단독으로는 배타 로직이 없어서, RadioField를 여러 개 나열해도 자동 배타가 안 됩니다. 예:
// ❌ 이건 작동 안 함 - 모두 체크될 수 있음
tags: [
{ tagName: 'radioField', label: '', radioLabel: '남성' },
{ tagName: 'radioField', label: '', radioLabel: '여성' }
]
사용자가 두 개를 다 클릭하면 둘 다 체크되어 시각적 혼란이 생깁니다.
진짜 실무에선:
// ✓ RadioGroupField 사용
{
tagName: 'radioGroupField',
label: '성별',
key: 'code',
display: 'name',
data: [
{ code: 'M', name: '남성' },
{ code: 'F', name: '여성' }
]
}
8. 언제 쓰나
RadioField 단독이 맞을 때 (극히 드묾)
- 커스텀 UI를 조립하며 라벨·검증만 붙이고 싶을 때
- 배타 로직을 개발자가 명시적으로 관리하는 경우
- 폼 안에서 "선택됨/미선택됨" 단일 상태를 시각적으로 라디오로 표현하고 싶을 때
RadioGroupField가 나을 때 (대부분)
- 여러 옵션 중 하나만 선택 (성별, 결제 방식, 등급)
- 배타 로직 자동
- 데이터 배열로 관리
다른 걸 쓸 때
- 여러 옵션 여러 개 선택 → CheckboxGroupField
- 단일 on/off → CheckboxField
- 스위치 UI → SwitchField
- 툴바 배타 → ToggleButton + ButtonGroup
9. 흔한 조합 예시 (단독 사용)
// 폼 안 단일 라디오 (특이 사례)
{
tagName: 'radioField',
label: '적용 여부',
radioLabel: '적용함',
onChange: 'onApply'
}
// 좌측 라벨 (폼 정렬)
{
tagName: 'radioField',
label: '상태',
labelPosition: 'left',
labelWidth: 100,
radioLabel: '활성',
checked: true
}
// 폼 라벨 없이
{
tagName: 'radioField',
noLabel: true,
radioLabel: '한 줄로 충분',
checked: false
}
// info 툴팁
{
tagName: 'radioField',
label: '기본 옵션',
radioLabel: '기본값 사용',
infoButton: {
tooltip: '체크 시 기본값으로 처리됩니다'
}
}
// 두 개를 수동으로 배타 관리하는 패턴 (권장 안 함)
class ManualRadio extends Va.View {
onSelectA(c, e, checked) { this._select('A'); }
onSelectB(c, e, checked) { this._select('B'); }
_select(key) {
this.getRef('rA').setChecked(key === 'A');
this.getRef('rB').setChecked(key === 'B');
this.selected = key;
}
config() {
return {
tagName: 'div',
tags: [
{ tagName: 'radioField', label: '', radioLabel: '옵션 A', ref: 'rA', onChange: 'onSelectA' },
{ tagName: 'radioField', label: '', radioLabel: '옵션 B', ref: 'rB', onChange: 'onSelectB' }
]
};
}
}
// ...위 코드는 RadioGroupField로 리팩터링 권장
10. 알아두면 좋을 주의사항
- RadioField 단독으로 배타 안 됨 — 여러 개 나열해도 자동 해제 없음. RadioGroupField 사용 권장.
- 두 라벨 개념 혼동 주의 — label은 폼 라벨, radioLabel은 라디오 옆 텍스트.
- change의 checked 인자는 항상 true — Radio는 클릭 시 무조건 true. 실질적 값은 어떤 컴포넌트가 콜백을 발생시켰는지로 판단.
- getChecked() valueType 반환 — '10'은 문자열, 'YN'은 문자열, 기본은 boolean.
- 옵션 키 radio — 세부 커스터마이즈용.
- 검증 자동 리셋 — keydown(Tab 제외)·select 시 이전 에러 자동 사라짐.
- noLabel: true로 폼 라벨만 숨기기 — radioLabel은 유지.
- required: true로 별표만 표시 — 미선택 시 검증은 개발자가 setValidation() 호출.
- radioLabelClick: false로 라벨 클릭 무시 — 실수 방지.
- focus()는 내부 Radio의 fieldWrapper에 포커스 — 실제 <input> 아님.
- 스페이스 키로 선택 — 표준 라디오 UX.
- 화살표 키 그룹 네비 없음 — 이것도 RadioGroup의 몫.
- 이벤트 리스너 등록 코드에 focus/blur 재발화 있음 — 다른 Field 형제와 일관.
11. radioField vs radioGroupField vs checkboxField 선택
상황추천
| 여러 옵션 중 하나만 | radioGroupField ✓ (Radio 단독 아님) |
| 단일 on/off 표현을 라디오로 | radioField (극히 드묾) |
| 여러 옵션 중 여러 개 | checkboxGroupField |
| 단일 동의 (약관 등) | checkboxField |
| ON/OFF 스위치 UI | switchField |
| 툴바 배타 토글 | toggleButton + buttonGroup |
| 세그먼트 배타 | segmentedControl |
12. 실전 원칙
"라디오는 그룹으로 쓴다" — 이 원칙만 지키면 실수를 안 합니다.
- 단일 상태 → checkboxField
- 배타 선택 → radioGroupField
- 세그먼트형 배타 → segmentedControl
RadioField 단독을 검토하고 있다면, 대부분 위 세 가지 중 하나로 대체할 수 있는지 먼저 확인하세요.