Va.Number — 숫자 전용 입력 필드
<input type="number">를 감싸는 PureField 계열 컴포넌트입니다. min/max/step/소수점 자릿수 제한을 옵션 하나로 지정할 수 있고, 브라우저 표준 스피너(위/아래 화살표) UI가 자동으로 붙습니다.
- 클래스: Va.Number — va_component.js:1257
- short name: number
- 상속: Va.PureField (Input/Search와 형제)
- DOM 태그: <input type="number"> (하드코딩)
- isContainer: true
- 베이스 CSS: va-input (Input과 동일 클래스 공유)

1. 기본 사용
{
tagName: 'number',
value: 10,
min: 0,
max: 100,
step: 1,
onChange: 'onQtyChange'
}
렌더 결과: <input type="number" step="1" min="0" max="100"> — 브라우저가 우측에 위/아래 스피너 버튼을 자동 표시.
2. Va.Input / Va.Search와의 차이
항목Va.InputVa.SearchVa.Number
| type 기본값 | 'text' (변경 가능) | 'search' 고정 | 'number' 고정 |
| 전용 속성 | numberComma | — | min / max / step / decimalPlaces |
| 초기 value | undefined | undefined | 0 |
| textAlign 기본 | 왼쪽 | 왼쪽 | 'right' (숫자 관행) |
| 브라우저 스피너 | ✕ | ✕ | ✓ (자동) |
| 모바일 키보드 | 텍스트 | 검색 | 숫자 전용 키패드 |
| 소수점 강제 자릿수 | ✕ | ✕ | ✓ (decimalPlaces) |
한 줄 요약: "숫자만 입력받고, min/max/step으로 범위를 강제하는 필드."
3. 주요 속성
Number 전용
속성기본값설명
| min | — | 최솟값 (HTML min 속성으로 반영) |
| max | — | 최댓값 (HTML max 속성으로 반영) |
| step | 1 | 스피너 증감 단위. 소수 허용 예: 0.1, 0.01 |
| decimalPlaces | — | 강제 소수점 자릿수. keyup마다 자동 반올림 (예: 2 → 1.239 입력 시 1.24로) |
PureField 상속
속성설명
| value | 필드 값 (숫자) — 기본 0 |
| placeholder | 플레이스홀더 |
| name | 폼 name |
| readonly / disabled | 상태 |
| required | 필수 표시 |
| textAlign | 정렬 — 기본 'right' |
| size / appearance | 크기·스타일 |
| masking | 마스킹 (숫자 필드에선 쓸 일 거의 없음) |
| maxLength | 최대 글자 수 (숫자에도 적용) |
⚠️ type 속성 변경 불가 — this.type = 'number'로 강제. text로 쓰려면 Va.Input 사용.
⚠️ numberComma 미지원 — Va.Input의 콤마 포맷 기능은 여기 없음. 콤마가 필요하면 Va.Input + numberComma:true + type:'number' 조합을 검토.
4. step — 증감 단위
브라우저 스피너 클릭 시(그리고 위/아래 화살표 키) 값이 얼마씩 바뀔지 결정합니다.
// 정수만 (기본)
{ tagName: 'number', step: 1 }
// 0.1 단위
{ tagName: 'number', step: 0.1, decimalPlaces: 1 }
// 100 단위 (금액 등)
{ tagName: 'number', step: 100, value: 1000 }
// 자유 입력 (검증만)
{ tagName: 'number', step: 'any' }
주의: step은 스피너/화살표 단위만 강제하는 것이지, 사용자가 키보드로 다른 값을 입력하는 걸 막지는 않습니다. 브라우저는 form submit 시에만 step에 어긋난 값을 invalid로 표시합니다.
5. decimalPlaces — 소수점 자릿수 강제
Number가 Input/Search와 크게 다른 지점입니다. keyup마다 값을 지정 자릿수로 반올림해 다시 세팅합니다 (va_component.js:1278-1284):
this._bindEvent(this.fieldElement,'keyup', (evt) => {
let value = this.fieldElement.value;
if (Va.Util.isNotBlank(this.decimalPlaces)) {
this.value = Va.Util.getFixedNumber(value, this.decimalPlaces);
this.setValue(this.value);
}
});
사용 예
// 소수 둘째자리까지
{ tagName: 'number', decimalPlaces: 2, step: 0.01, value: 3.14 }
// 정수만
{ tagName: 'number', decimalPlaces: 0 }
// 소수 넷째자리까지 (환율 등)
{ tagName: 'number', decimalPlaces: 4, step: 0.0001 }
setValue()도 자동으로 자릿수를 강제합니다 (va_component.js:1307-1312).
⚠️ 입력 중 사용자 경험이 어색할 수 있음 — 사용자가 1.239를 다 못 치기 전에 반올림이 일어나면 입력이 튈 수 있음. 실시간 반올림이 문제라면 blur 시점으로 옮기는 커스터마이즈 검토.
6. min / max — 범위 제한
HTML 표준 속성으로 반영됩니다. 브라우저 스피너와 form validation에만 실효가 있고, 키보드 직접 입력은 막지 못합니다.
{
tagName: 'number',
min: 0,
max: 100,
value: 50
}
정확한 범위 강제가 필요하면:
- change 이벤트에서 component.getValue()를 체크 후 벗어나면 clamp
- 또는 NumberField로 감싸 setValidation()으로 에러 메시지 표시
onChange(component, element, evt) {
const v = Number(component.getValue());
if (v < component.min) component.setValue(component.min);
if (v > component.max) component.setValue(component.max);
}
7. 이벤트 (PureField 상속)
Input과 동일:
이벤트시그니처
| change | (component, element, evt) |
| focus / blur | (component, element, evt) — blur 200ms debounce |
| click | (component, element, evt) |
| keydown | (component, element, keyCode, evt) |
| keyup | (component, element, keyCode, evt) — decimalPlaces 반올림이 여기서 발생 |
| keypress / contextmenu / mousedown | 표준 |
주목: decimalPlaces가 켜져 있으면 keyup 때마다 값이 재세팅되면서 change도 함께 튀는 상황이 생길 수 있습니다.
8. 메서드 (PureField 상속 + 오버라이드)
메서드설명
| getValue() | 현재 값 반환 — 문자열로 반환됨 (fieldElement.value가 항상 string). 숫자 계산엔 Number(component.getValue()) 필요 |
| setValue(value) | 오버라이드됨 — decimalPlaces가 있으면 자동 반올림 후 세팅 |
| setDisabled(bool) / disable() / enable() | 상태 |
| setReadOnly(bool) / setReadonly(bool) | 읽기 전용 |
| focus() / blur() | 포커스 제어 |
9. 내부 구조
Input과 동일한 PureField 구조:
<div elname="element" class="va-input [size] [focused] ..." tag-name="input" field="true">
<div elname="fieldWrapper" class="field-wrapper">
<input elname="field" type="number" step="1" min="..." max="..." style="border:0px">
<div elname="focusLine" class="focus-line"></div>
</div>
</div>
차이는 <input>의 type="number" 속성과 step/min/max 속성이 붙는 것뿐.
10. 브라우저 스피너 (위/아래 화살표) 특성
<input type="number">의 표준 UI인데, 프로젝트에 따라 숨기고 싶을 때가 많습니다.
숨기는 CSS (자주 필요):
/* Chrome, Safari, Edge */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
프로젝트 CSS(va.css 또는 테마)에 이미 정의되어 있을 수 있으니 확인해 보세요.
11. 언제 쓰나
Number가 맞을 때
- 수량·개수·나이 입력 (정수)
- 금액 입력 (스피너 없이 쓰거나, step:1000 등)
- 소수점 자릿수를 강제해야 하는 값 (평점 3.5, 환율 등)
- 모바일에서 숫자 키패드가 뜨면 좋을 때
- 브라우저 스피너로 조작 편의 제공
다른 걸 쓸 때
- 스피너 + 별도 -/+ 버튼이 필요하면 → Va.NumberWithButton (같은 계열의 확장 컴포넌트)
- 라벨 붙은 폼 필드 → Va.NumberField
- 금액에 콤마 포맷(1,234,567) → Va.Input + numberComma:true
- 큰 정수·전화번호 등 숫자지만 계산 안 하는 값 → Va.Input (type:'tel' 검토)
12. 알아두면 좋을 주의사항
- getValue()는 문자열 반환 — 계산엔 Number() 변환 필수. 특히 + 연산자로 문자열 연결 사고 조심.
- min/max는 키보드 입력 못 막음 — 정확한 범위 강제는 change 콜백에서 처리 필요.
- decimalPlaces 실시간 반올림 UX — 사용자가 소수 입력 중일 때 값이 튀는 느낌이 있음. 필요하면 blur 시점 반올림으로 커스터마이즈.
- 초기 value가 0 — 옵션에 value를 안 넘기면 0이 표시됨. Input처럼 빈 값으로 시작하고 싶으면 value: '' 명시.
- 초기 textAlign이 'right' — 숫자 필드 관행. 왼쪽 정렬이 필요하면 textAlign: 'left' 명시.
- type 변경 불가 — 필요하면 Input 사용.
- numberComma 미지원 — 콤마 포맷은 여기 없음.
- 크롬 스피너가 폼 폭 잡아먹음 — 얇은 필드에선 스피너 CSS로 숨기는 게 낫습니다.
- 한글 IME/음성 입력 — type="number"는 문자 입력을 아예 차단하는 브라우저가 많아 IME 조합 이슈 최소화 효과.
- step="any" — 자유 소수 입력 허용 (기본은 정수만 스피너로 조작).
13. 흔한 조합 예시
// 수량 (0~999)
{ tagName: 'number', min: 0, max: 999, step: 1, value: 1 }
// 평점 (0.0~5.0)
{ tagName: 'number', min: 0, max: 5, step: 0.1, decimalPlaces: 1, value: 3.5 }
// 금액 (1000원 단위)
{ tagName: 'number', min: 0, step: 1000, value: 10000, textAlign: 'right' }
// 환율 (소수 넷째자리)
{ tagName: 'number', step: 0.0001, decimalPlaces: 4, value: 1300.1234 }
// 나이 (정수만, 상한)
{ tagName: 'number', min: 0, max: 150, step: 1, value: 25 }
'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글
| ColorPicker(색상선택) (0) | 2026.09.10 |
|---|---|
| NumberField (숫자필드) (0) | 2026.09.10 |
| SearchField (검색필드) (0) | 2026.09.10 |
| Search (검색) (0) | 2026.09.10 |
| InputField (입력필드) (0) | 2026.09.09 |