컴포넌트/필드 컴포넌트

TimeField (시각필드)

VanillaFront 2026. 9. 12. 19:13

Va.TimeField — 라벨 + 시간(시·분·초) 선택 필드

Va.TimePicker가 순수 시간 입력이라면, Va.TimeField는 그 위에 라벨·필수 표시·검증 메시지를 얹은 완성 폼 필드입니다. Field 계열 아키텍처 그대로, 내부에 Va.TimePicker를 소유하는 Composition 구조. 근태·회의 시간대·영업 시간 같은 폼 필드에 최적화되어 있어요.

  • 클래스: Va.TimeField  va_component.js:8873
  • short name: timeField
  • 상속: Va.Field (다른 Field 형제들과 같음)
  • 내부 컴포넌트: Va.TimePicker 인스턴스 (fieldComponent)
  • isContainer: true
  • 베이스 CSS: va-field (role="time-field" 자동 부여 — 다른 Date 계열과 다름!)


1. 기본 사용

{
    tagName: 'timeField',
    label: '출근 시각',
    value: '090000',              // HHMMSS 6자리
    required: true,
    onSelect: 'onTimeChange'
}

라벨 + 검증 + 시·분·초 드롭다운 팝업이 한 번에 세팅. 저장 값은 6자리 또는 4자리 문자열 (timeFormat에 따라).


2. Field 계열에서의 위치

Va.Field
   ├─ Va.InputField         ← Va.Input
   ├─ Va.SearchField        ← Va.Search
   ├─ Va.NumberField        ← Va.Number
   ├─ Va.ComboboxField      ← Va.Combobox
   ├─ Va.YearField          ← Va.YearPicker         (년만)
   ├─ Va.MonthField         ← Va.MonthPicker        (년-월)
   ├─ Va.DateField          ← Va.DatePicker         (년-월-일)
   ├─ Va.DateTimeField      ← Va.DateTimePicker     (년-월-일 + 시분초)
   ├─ Va.TimeField          ← Va.TimePicker         (시분초만)      ← 이 문서
   └─ ...

TimeField의 정체: Field 베이스 + 내부에 Va.TimePicker 인스턴스. Date 계열 Field 중 유일하게 role="time-field" 를 부여합니다.


3. Va.TimePicker / 다른 Date 계열 Field와의 차이

항목Va.TimePickerVa.TimeFieldVa.DateFieldVa.DateTimeField

라벨
검증 메시지
info 툴팁
입력 대상 시분초 시분초 년-월-일 년-월-일 + 시분초
저장 값 길이 6/4자리 6/4자리 8자리 14/12자리
팝업 UI 시·분·초 드롭다운 시·분·초 드롭다운 (내부 위임) 캘린더 캘린더 + 시분초
role="time-field" 자동 ✓ (유일) date-field date-field
change/keydown 시 검증 자동 리셋

한 줄 요약: "폼 안 라벨 붙은 시각 필드 — 근태·회의·영업 시간에 최적."


4. 주요 속성

시간 포맷

속성기본값설명

timeFormat 'hhmmss' 시간 표시 형식. hhmmss / hhmm / hm
timeSeperator ':' 시간 구분자
valueTimeFormat 저장 시간 형식
valueTimeSeperator 저장 시간 구분자
masking 자동 (__:__:__ 또는 __:__) timeFormat에 따라 자동

팝업

속성기본값설명

popWidth 240 팝업 폭
expanded false 초기 상태

라벨 (Field 상속)

속성설명

label 라벨 텍스트 또는 객체
labelPosition top / bottom / left / right
labelWidth 라벨 폭
noLabel 라벨 숨김
infoButton info 아이콘
required 필수 표시

필드 관련 (TimePicker로 위임)

속성설명

value 시각 값 (HHMMSS 또는 HHMM 문자열)
placeholder 플레이스홀더
readonly / disabled 상태
size / appearance / shape 시각 스타일
textAlign 정렬
stopPropagation 이벤트 버블링

검증

속성설명

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

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

{
    tagName: 'timeField',
    label: '출근',
    timePicker: {                 // ← 내부 TimePicker에 전달
        popWidth: 320
    }
}

TimeField는 옵션 키가 정확히 timePicker — 다른 Field 형제와 마찬가지로 자기 내부 Picker 이름을 씀. MonthField(monthPicker)와 같은 관행.

각 Field 계열 옵션 키:

  • InputField → input
  • ComboboxField → combobox
  • DateField / DateTimeField → datePicker
  • YearField → monthPicker (잔재)
  • MonthField → monthPicker
  • TimeField → timePicker

⚠️ 참고: TimeField는 생성자에서 내부적으로 Va.MenuButton도 하나 만들어둡니다 (va_component.js:8899-8910). 옵션 menuButton으로 세부 조정 가능 — 실사용에선 잘 안 씀.


5. 저장 값 길이

timeFormat에 따라 달라집니다:

timeFormat화면 표시저장 값길이

hhmmss (기본) 14:30:00 143000 6자리
hhmm / hm 14:30 1430 4자리

valueTimeSeperator 지정 시 저장 값에도 구분자 삽입:

{ valueTimeSeperator: ':' }
// 저장: '14:30:00' 또는 '14:30'

6. 이벤트

TimePicker의 이벤트를 재발화:

이벤트시그니처발생 시점

select (component, element, value, evt) 팝업 "Confirm" 클릭 시. value는 원시 값
beforePop / afterPop / hidePop 팝업 표시/숨김  
expand / collapse 팝업 확장/축소  
focus / blur 표준  
change / keydown Field 표준 (검증 자동 리셋)  

⚠️ select 이벤트 dispatch가 두 번 — 소스 va_component.js:8961va_component.js:8991에서 각각 등록. 첫 번째는 짧은 인자(this, this.element, evt), 두 번째는 긴 인자(this, this.element, value, evt). 콜백 중복 실행 위험. 방어 코드 필요.

⚠️ TimePicker의 즉시 선택 아님 — 팝업의 시·분·초 드롭다운을 조작해도 이벤트 안 나옴. "Confirm" 버튼을 눌러야 select 발생 + 값 반영.


7. 메서드

값 관리 (Field 상속 그대로)

메서드설명

getValue() 내부 TimePicker의 getValue() 위임 (valueTimeSeperator 규약, 미완성이면 '')
setValue(value) Field 상속 — 내부 TimePicker에 위임

주목: TimeField는 setValue() / getValue()를 오버라이드하지 않습니다. 값 처리 전체를 내부 TimePicker에 맡겨요.

상태 (Field 상속)

메서드설명

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

검증

메서드설명

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

포커스

메서드설명

focus() / blur() 내부 TimePicker의 fieldElement에 위임

주의: showTimePickerPop, hideTimePickerPop, setRawValue, getRawValue 같은 TimePicker 세부 메서드는 위임 없음. 필요하면 component.fieldComponent.xxx()로 직접.


8. 내부 구조

<div elname="element" class="va-field [vertical|horizontal]"
     role="time-field" 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-timepicker">      ← 내부 Va.TimePicker
        <div class="field-wrapper">
          <input type="text" placeholder="__:__:__">
          <div class="focus-line"></div>
          <div class="clock-icon-wrapper">
            <span class="icon menu ico_clock_fill">🕐</span>
          </div>
        </div>
        <!-- 팝업은 hiddenArea로 이동 -->
      </div>
    </div>
  </div>
  <div elname="validationDiv" style="display:none">
    <div class="va-validation">...</div>
  </div>
</div>

주목: role="time-field" — Date 계열 Field(date-field)와 유일하게 다름. 스크린리더가 시간 필드로 정확히 인식.


9. 언제 쓰나

TimeField가 맞을 때

  • 폼 안 근태 출퇴근 시각 입력
  • 회의 시간대 선택 (13:00 회의 등)
  • 알람·리마인더 시각
  • 영업 시간 설정 (오픈·마감)
  • 알림 발송 시각 등록
  • 라벨·필수·검증이 필요한 시각 필드

다른 걸 쓸 때

  • 라벨 없이 인라인 → Va.TimePicker
  • 날짜도 필요 → Va.DateTimeField (조합 컴포넌트)
  • 시작~종료 시각 → 두 TimeField 조합
  • 15분·30분 단위만 → Va.ComboboxField (스텝 옵션 없음)
  • 12시간 AM/PM → 커스텀 (기본 지원 안 됨)

10. 흔한 조합 예시

// 표준 (초까지)
{
    tagName: 'timeField',
    label: '출근 시각',
    value: '090000',
    required: true
}

// 분까지만
{
    tagName: 'timeField',
    label: '알람 시각',
    timeFormat: 'hhmm',
    value: '0700'
}

// 서버가 콜론 포함 원할 때
{
    tagName: 'timeField',
    label: '오픈 시간',
    valueTimeSeperator: ':',
    value: '09:00:00'
}

// 좌측 라벨
{
    tagName: 'timeField',
    label: '퇴근 시각',
    labelPosition: 'left',
    labelWidth: 100,
    value: '180000'
}

// info 툴팁
{
    tagName: 'timeField',
    label: '알림 시각',
    infoButton: {
        tooltip: 'KST 기준 시각으로 발송됩니다'
    }
}

// 지금 시각으로 초기화
mounted() {
    const now = new Date();
    const hhmmss = String(now.getHours()).padStart(2, '0') +
                   String(now.getMinutes()).padStart(2, '0') +
                   String(now.getSeconds()).padStart(2, '0');
    this.getRef('time').setValue(hhmmss);
}

// 검증
{
    tagName: 'timeField',
    label: '회의 시작',
    ref: 'startTime',
    required: true,
    onSelect: 'onStartTimePicked'
}

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

  1. 컴포넌트명  timeField (not timePickerField).
  2. role="time-field"가 유일하게 다름 — Date 계열 Field는 모두 date-field인데 TimeField만 time-field. 스크린리더 대응은 오히려 이쪽이 정확.
  3. value는 4자리 또는 6자리 문자열 — timeFormat에 따라. Date 객체 넘기면 크래시.
  4. select 이벤트 두 번 dispatch — 콜백 방어 필요.
  5. "Confirm" 버튼 눌러야 값 확정 — 팝업 드롭다운 조작만으로는 안 됨. DatePicker와 UX 다름.
  6. getValue()가 미완성 값에 '' 반환 — 마스킹 언더스코어 있으면 빈 문자열.
  7. 잘못된 형식 검증 없음  99:99:99 같은 값도 완성되면 그대로 반환.
  8. 12시간 AM/PM 미지원 — 24시간 형식 고정.
  9. 15분·30분 스텝 미지원 — 1분 단위. 별도 스텝 옵션 없음.
  10. 옵션 키 timePicker — 내부 커스터마이즈 시 이 키 사용.
  11. popWidth 기본 240 — 시·분·초 3개 드롭다운엔 충분.
  12. change/keydown 시 검증 자동 리셋 — 사용자가 값 수정하면 이전 에러 자동으로 사라짐.
  13. 일부 메서드 위임 누락  showPop/hidePop/setRawValue/getRawValue. fieldComponent로 직접.
  14. timezone 없음 — 로컬 시각 문자열만.
  15. fieldElement = this.tagName = 'timeField' 문법 오류성 코드  va_component.js:8876-8877  this.fieldElement = this.tagName = 'timeField' — 표면적으로는 동작하나 이상한 초기화. 이후 this.fieldElement = this.fieldComponent.fieldElement로 재할당되어 실질적 문제는 없음.

12. 실전 예 — 근태 출퇴근 시각 (Field 버전)

TimePicker 편의 예제를 Field로 감싼 버전:

class Attendance extends Va.View {
    mounted() {
        this.getRef('startTime').setValue('090000');
        this.getRef('endTime').setValue('180000');
    }

    onSubmit(btn, el, evt) {
        const start = this.getRef('startTime').getValue();
        const end   = this.getRef('endTime').getValue();

        if (!start) {
            this.getRef('startTime').setValidation('error', '출근 시각을 입력하세요');
            return;
        }
        if (!end) {
            this.getRef('endTime').setValidation('error', '퇴근 시각을 입력하세요');
            return;
        }
        if (Number(end) <= Number(start)) {
            this.getRef('endTime').setValidation('error', '퇴근 시각이 출근 시각보다 늦어야 합니다');
            return;
        }

        AttendanceService.save(this, {
            date:      '20241225',
            startTime: start,
            endTime:   end
        }, this.onSaved);
    }

    onSaved(view, ok, res) {
        if (ok) new Va.Alert({ title: '완료', message: '저장되었습니다' }).show(view);
    }

    config() {
        return {
            tagName: 'page',
            tags: [{
                tagName: 'panel',
                tags: [
                    { tagName: 'h2', innerHTML: '근태 등록' },
                    {
                        tagName: 'div',
                        layout: 'ds-flex fd-row ai-end gap-m',
                        tags: [
                            {
                                tagName: 'timeField',
                                ref: 'startTime',
                                label: '출근 시각',
                                required: true,
                                style: { width: '180px' }
                            },
                            {
                                tagName: 'timeField',
                                ref: 'endTime',
                                label: '퇴근 시각',
                                required: true,
                                style: { width: '180px' }
                            }
                        ]
                    },
                    {
                        tagName: 'button',
                        text: '저장',
                        appearance: 'primary',
                        onClick: 'onSubmit'
                    }
                ]
            }]
        };
    }
}

TimePicker 단독 사용과 비교하면 라벨 + 필수 표시 + 검증 메시지 + ARIA 시각 필드 role이 자동 세팅되어 폼 UX가 자연스럽습니다.


13. timeField vs dateTimeField 선택 기준

상황추천

근태 출퇴근 시각 (날짜는 별도 필드) timeField
알람 시각, 리마인더 시각 timeField
영업 시간 설정 (오픈·마감) timeField
회의 시간 (요일 반복) timeField
특정 날짜의 특정 시각 (예약, 마감) dateTimeField
로그 타임스탬프 편집 dateTimeField
게시글 예약 발행 dateTimeField

"날짜가 매일 반복되는 시각"이면 timeField, "특정 날짜의 시각"이면 dateTimeField.

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

CheckboxField (체크박스필드)  (0) 2026.09.12
Checkbox (체크박스)  (0) 2026.09.12
TimePicker (시각선택)  (0) 2026.09.12
MonthField (년월필드)  (0) 2026.09.12
MonthPicker (월선택)  (0) 2026.09.12