컴포넌트/필드 컴포넌트

NumberField (숫자필드)

VanillaFront 2026. 9. 10. 14:59

Va.NumberField — 라벨 + 숫자 입력 + 검증까지 감싼 폼 필드

Va.Number가 순수 숫자 입력이라면, Va.NumberField는 그 위에 라벨·필수 표시·검증 메시지·설명 텍스트를 얹은 "완성된 숫자 폼 필드" 입니다. Field 계열의 3형제(InputField, SearchField, NumberField)와 같은 아키텍처를 따르되, 내부에 Va.Number를 소유합니다.

  • 클래스: Va.NumberField — va_component.js:5494
  • short name: numberField
  • 상속: Va.Field (InputField·SearchField와 형제)
  • 내부 컴포넌트: Va.Number 인스턴스를 자식으로 소유 (fieldComponent)
  • isContainer: true
  • 베이스 CSS: va-field


1. 기본 사용

{
    tagName: 'numberField',
    label: '수량',
    value: 10,
    min: 0,
    max: 100,
    step: 1,
    required: true,
    onChange: 'onQtyChange'
}

라벨 · 필드 · 검증 영역이 자동 세팅되고, 내부 <input type="number">가 스피너까지 제공.


2. Field 3형제와의 위치

세 Field 컴포넌트가 완전히 같은 패턴으로 만들어져 있어 한 번에 정리:

Va.Field
   ├─ Va.InputField     ← 내부에 Va.Input      (text)
   ├─ Va.SearchField    ← 내부에 Va.Search     (search)
   ├─ Va.NumberField    ← 내부에 Va.Number     (number)    ← 이 문서
   ├─ Va.TextareaField
   ├─ Va.ComboboxField
   └─ ...

세 개 모두:

  • 라벨/검증/설명 영역 = Field 베이스가 제공
  • 실제 입력창 = 내부 PureField 계열 인스턴스가 담당
  • 옵션 spread + _syncProperties 패턴 동일

차이는 딱 세 가지:

  1. 내부에 어떤 PureField를 생성하는가 (Va.Number)
  2. 세부 커스터마이즈 옵션 키 (number)
  3. Number 전용 속성 추가 (min / max / step)

3. Va.Number / Va.InputField와의 차이

항목Va.NumberVa.NumberFieldVa.InputField

라벨 ✕ ✓ ✓
검증 메시지 ✕ ✓ ✓
설명 텍스트 ✕ ✓ ✓
info 툴팁 ✕ ✓ ✓
input type number 고정 number 고정 text 기본
min / max / step ✓ ✓ (전용 속성) ✕ (input 옵션으로만)
textAlign 기본 'right' 'right' 왼쪽
브라우저 스피너 ✓ ✓ ✕

4. 주요 속성

Number 전용 속성 (Field 위에서도 유효)

속성기본값설명

min — 최솟값
max — 최댓값
step (내부 Number 기본 1) 스피너 증감 단위

주목: 이 세 개가 Field 자체의 properties에 추가되어 있습니다 (va_component.js:5500). InputField/SearchField와의 차이. 그래서 setOption()이 인식하고 _syncProperties()로 내부 Number에도 자동 반영됩니다.

⚠️ decimalPlaces는 NumberField의 명시 속성이 아님 — 하지만 number 옵션 통해서 넘길 수는 있습니다 (아래 참조).

라벨 관련 (Field 상속)

속성기본값설명

label — 라벨 텍스트 또는 옵션 객체
labelPosition 'top' top / bottom / left / right
labelWidth 자동 라벨 영역 폭
labelAlign — 라벨 정렬
noLabel false 라벨 영역 숨김
infoButton — 라벨 옆 info 아이콘 (툴팁)
required false 필수 표시

필드 관련 (Number로 위임)

속성설명

value 필드 값
placeholder 플레이스홀더
readonly / disabled 상태
textAlign 정렬 — 기본 'right' (숫자 관행)
size / appearance / shape 시각 스타일
masking 마스킹 (거의 안 씀)
valueType 값 타입 힌트

검증

속성설명

validation {state, size, message} 객체
validationState success / warning / error
validationMessage 메시지 텍스트
validationSize 메시지 크기

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

{
    tagName: 'numberField',
    label: '평점',
    min: 0,
    max: 5,
    step: 0.1,
    number: {                       // ← 내부 Number에 직접 전달
        decimalPlaces: 1,
        autocomplete: 'off'
    }
}

number 객체는 va_component.js:5524에서 내부 Va.Number 생성 시 spread됩니다. 특히 decimalPlaces는 이 통로로 넘겨야 반영됩니다 (Field 자체 속성엔 선언 안 되어 있음).

각 Field 계열의 옵션 키가 다릅니다 — InputField는 input, SearchField는 search, NumberField는 number.


5. 이벤트 (Field 상속)

Input/Search Field와 완전히 동일:

이벤트시그니처발생 시점

change (component, element, evt) 값 변경 확정. 발생 시 검증 자동 리셋
focus / blur (component, element, evt) blur 200ms debounce
click (component, element, evt) 필드 클릭
keydown (component, element, keyCode, evt) 검증 자동 리셋
keyup (component, element, evt) —
keypress (component, element, evt) —
contextmenu / mousedown 표준  

6. 메서드 (Field 상속)

InputField·SearchField와 완전히 동일:

값

메서드설명

getValue() 내부 Number의 getValue() 위임 (문자열 반환 — 계산엔 Number() 변환 필요)
setValue(value) 값 세팅 + 검증 자동 리셋 (내부 Number가 decimalPlaces 적용)

상태

메서드설명

setDisabled(bool) / getDisabled() 비활성화
setReadOnly(bool) / setReadonly(bool) 읽기 전용
setLabel(label) 라벨 변경
setPlaceholder(text) 플레이스홀더 변경
setSize(size) 크기 변경

검증

메서드설명

setValidation(state, message) 검증 표시 + aria 자동 세팅
clearValidation() 검증 해제

포커스

메서드설명

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

주의: setMin / setMax / setStep 같은 편의 setter는 없습니다. 값 변경이 필요하면 component.min = ...; component.update()로 직접.


7. 내부 구조

<div elname="element" class="va-field va-input [vertical|horizontal] [disabled]" 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-input">              ← 내부 Va.Number
        <div class="field-wrapper">
          <input type="number" step="1" min="0" max="100" ...>
          <div class="focus-line"></div>
        </div>
      </div>
    </div>
  </div>
  <div elname="validationDiv" style="display:none">
    <div class="va-validation">...</div>
  </div>
</div>

InputField/SearchField와 구조 동일, 안쪽 input의 type="number" + step/min/max 속성만 다름.


8. 언제 쓰나

NumberField가 맞을 때

  • 폼 안 숫자 입력 필드 (수량·나이·평점·금액)
  • 라벨과 함께 필수 표시·검증 메시지가 필요할 때
  • 범위 제한(min/max)이 명확한 값
  • 소수점 자릿수 강제(number.decimalPlaces)가 필요한 값

다른 걸 쓸 때

  • 라벨 없는 인라인 숫자 입력 → Va.Number
  • ±버튼이 좌우에 붙은 형태 → Va.NumberWithButtonField
  • 금액에 콤마 포맷 → Va.InputField + input.numberComma:true
  • 텍스트+숫자 혼합 (전화번호, 신용카드 등) → Va.InputField + masking

9. 흔한 조합 예시

// 수량
{
    tagName: 'numberField',
    label: '수량',
    min: 0,
    max: 999,
    step: 1,
    value: 1,
    required: true
}

// 평점 (0~5, 소수 첫째)
{
    tagName: 'numberField',
    label: '평점',
    min: 0,
    max: 5,
    step: 0.1,
    number: { decimalPlaces: 1 },
    value: 3.5
}

// 금액 (1000원 단위 스피너)
{
    tagName: 'numberField',
    label: '금액',
    min: 0,
    step: 1000,
    value: 10000,
    textAlign: 'right'
}

// 환율 (소수 넷째)
{
    tagName: 'numberField',
    label: '환율',
    step: 0.0001,
    number: { decimalPlaces: 4 },
    value: 1300.1234
}

// 나이 (info 툴팁 포함)
{
    tagName: 'numberField',
    label: '나이',
    min: 0,
    max: 150,
    infoButton: {
        tooltip: '만 나이 기준으로 입력하세요'
    }
}

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

  1. getValue()는 문자열 — 계산엔 Number(component.getValue()) 변환 필수.
  2. min/max는 키보드 직접 입력 못 막음 — 정확한 범위 강제는 change 콜백에서 clamp하거나 setValidation('error', ...)으로 알림.
  3. decimalPlaces는 number 옵션으로만 — Field 자체 속성엔 없음. {number: {decimalPlaces: 2}} 형태로 전달.
  4. type 변경 불가 — 'number' 고정. text로 쓰려면 InputField 사용.
  5. numberComma 미지원 — 금액 콤마 필요하면 InputField + numberComma 조합.
  6. 초기 value가 0 — 빈 값 시작 원하면 value: '' 명시 (내부 Number의 기본값).
  7. textAlign 기본 'right' — 숫자 관행. 왼쪽 정렬 필요하면 명시.
  8. change/keydown 시 검증 자동 리셋 — 사용자가 값을 수정하기 시작하면 이전 에러가 사라짐.
  9. 브라우저 스피너 UX — 스피너 폭이 필드 오른쪽을 잡아먹음. 얇은 필드에선 CSS로 숨기는 게 나을 수 있음.
  10. decimalPlaces 실시간 반올림 UX 주의 — 사용자가 소수 입력 중일 때 값이 튀는 느낌이 있음 (내부 Number의 keyup 동작).
  11. 옵션 키가 number — InputField의 input, SearchField의 search와 헷갈리지 말 것.
  12. 필수 검증 자동화는 없음 — required: true는 라벨 별표만 표시. 실제 값 존재 검증은 콜백에서 setValidation() 호출로 처리.