컴포넌트

DatePicker (날짜선택)

VanillaFront 2026. 9. 10. 15:37

Va.DatePicker — 캘린더 팝업이 있는 날짜 선택 필드

날짜를 입력받는 컴포넌트. 좌측에 날짜 마스킹(YYYY-MM-DD) 입력창, 우측에 캘린더 아이콘이 있고, 아이콘 클릭 또는 Enter 시 월간 캘린더 팝업이 열립니다. ColorPicker와 같은 팝업 패턴을 따르되, 내부에 달력 렌더링 로직이 붙어 있습니다.

  • 클래스: Va.DatePicker  va_component.js:6654
  • short name: datePicker
  • 상속: Va.PureField (Input/Combobox와 형제)
  • isContainer: true
  • 베이스 CSS: va-input (팝업은 va-menu-pop, 달력은 calendar-inner)
  • 소스 크기: 약 566줄


1. 기본 사용

{
    tagName: 'datePicker',
    value: '20241225',                    // 저장 값은 YYYYMMDD (구분자 없이)
    dateFormat: 'ymd',                    // 화면 표시 순서
    dateSeperator: '-',                   // 화면 구분자
    onSelect: 'onDateSelect'
}
  • 화면 표시: 2024-12-25
  • 저장 값(getValue()): 20241225
  • 필드에 직접 타이핑도 가능 (마스킹 적용)

2. 다른 PureField 계열과의 차이

항목Va.InputVa.ComboboxVa.DatePicker

입력 방식 자유 텍스트 팝업 리스트 캘린더 팝업 + 마스킹 타이핑
팝업 리스트 캘린더 (년/월 이동, 오늘 버튼)
마스킹 옵션 자동 (____-__-__)
저장 값 형식 그대로 그대로 YYYYMMDD 8자리 (기본)
화면 표시 순서 ymd / mdy / dmy 선택
최소/최대 날짜 min / max
캘린더 아이콘 화살표(▼) 캘린더 아이콘

한 줄 요약: "화면 표시 포맷과 저장 값 포맷을 분리해서 관리하는 날짜 입력."


3. 주요 속성

날짜 포맷

속성기본값설명

dateFormat 'ymd' 화면 표시 순서  ymd / mdy / dmy
dateSeperator '-' 화면 구분자  -, /, . 
valueDateFormat 'ymd' 저장 값 순서 — 서버 규약에 맞춤
valueDateSeperator '' 저장 값 구분자 — 기본 없음 (20241225 형태). '-'면 2024-12-25
masking 자동 (____-__-__) dateFormat/dateSeperator에 따라 자동 설정

핵심 개념 — 화면 값과 저장 값 분리:

{
    tagName: 'datePicker',
    dateFormat: 'mdy',        // 화면: 12-25-2024
    dateSeperator: '-',
    valueDateFormat: 'ymd',   // 저장: 20241225 (서버가 원하는 형태)
    valueDateSeperator: ''
}

미국식 표시(MM-DD-YYYY)로 사용자에게 보여주면서 서버엔 YYYYMMDD로 저장, 같은 컴포넌트로 처리 가능.

범위

속성설명

min 최소 선택 가능 날짜 (YYYYMMDD 문자열)
max 최대 선택 가능 날짜

팝업

속성기본값설명

expanded false 팝업 초기 상태
popWidth 260 팝업 폭

PureField 상속

value, placeholder, readonly, disabled, size, appearance, stopPropagation 등 모두 유효.


4. 날짜 포맷 조합 예시

한국 표준 (기본)

{ tagName: 'datePicker' }
// 화면: 2024-12-25
// 저장: 20241225

미국 표시 + 서버 저장

{
    tagName: 'datePicker',
    dateFormat: 'mdy',
    dateSeperator: '/',
    valueDateFormat: 'ymd'
}
// 화면: 12/25/2024
// 저장: 20241225

유럽 표시 + ISO 저장

{
    tagName: 'datePicker',
    dateFormat: 'dmy',
    dateSeperator: '.',
    valueDateFormat: 'ymd',
    valueDateSeperator: '-'
}
// 화면: 25.12.2024
// 저장: 2024-12-25

범위 제한

{
    tagName: 'datePicker',
    min: '20240101',
    max: '20241231',
    value: '20240315'
}

5. 이벤트

이벤트시그니처발생 시점

select (component, element, value, evt) 캘린더에서 날짜 클릭 시. value는 선택된 날짜
beforePop / afterPop / hidePop 팝업 표시/숨김  
expand / collapse 팝업 확장/축소  
focus / blur 표준 (blur 200ms debounce)  
change 필드 값 변경 (직접 타이핑 등)  
keydown / keyup 키 이벤트  

6. 메서드

값 관리 — 두 벌의 setter/getter

DatePicker는 값 세팅 방식이 두 가지입니다:

메서드설명

setValue(value) valueDateFormat 규약을 따르는 값 세팅 (서버에서 받은 값을 세팅할 때)
getValue() valueDateFormat 규약을 따르는 값 반환 (서버로 전송할 때)
setRawValue(value) 항상 YYYYMMDD 원시 값 세팅 (내부용)
getRawValue() 항상 YYYYMMDD 원시 값 반환 (내부용)
getDisplay() 화면에 표시되는 형태 그대로 반환 (dateFormat+dateSeperator 적용)

동작 흐름:

  • setValue('20241225') → valueDateFormat 규약 해석 → 내부 저장은 YYYYMMDD → 화면은 dateFormat/dateSeperator로 변환 표시
  • getValue() → 화면 값 파싱 → valueDateFormat/valueDateSeperator에 맞춰 반환

팝업 제어

메서드설명

showDatePickerPop(evt) 팝업 강제 열기
hideDatePickerPop() 팝업 강제 닫기
showPop() drawCalendar() 호출 (레거시)
hidePop() expanded=false + update()
drawCalendar() 캘린더 렌더링 (내부)

상태 (PureField 상속)

메서드설명

setDisabled(bool) / setReadOnly(bool) 상태
focus() / blur() 포커스

7. 팝업 캘린더 UI

drawCalendar()가 렌더링하는 구성:

  • 헤더: 년월 이동 화살표 (buttonLeft, buttonRight), 년/월 표시
  • 본문: 7열 × 6행 날짜 그리드 (일 ~ 토)
  • "오늘" 버튼: 오늘 날짜로 즉시 세팅
  • 선택된 날짜 강조
  • min / max 범위 밖 날짜 비활성화

버튼들은 innerComponents에 등록됨: buttonLeft, buttonRight, buttonToday (va_component.js:6661-6662)


8. 내부 구조

<div elname="element" class="va-input [size] [focused]..." tag-name="datePicker" field="true">
  <div elname="fieldWrapper" class="field-wrapper">
    <input elname="field" type="text" placeholder="____-__-__"
           style="border:0px">                              ← 마스킹 필드
    <div elname="focusLine" class="focus-line"></div>
    <div elname="calendarIconWrapper">
      <span elname="calendarIcon" class="icon menu ico_calender_ltr">📅</span>
    </div>
  </div>
  <div elname="popDiv" class="menu-button-pop-div">
    <div elname="pop" class="va-menu-pop" style="position:absolute; display:none">
      <div elname="popInner" class="calendar-inner">
        <!-- 년월 헤더 + 날짜 그리드 + 오늘 버튼 -->
      </div>
    </div>
  </div>
</div>

핵심 트릭:

  • 팝업이 열릴 때 getHiddenAreaElement()로 이동해 부모 stacking 회피
  • 자동 위치 조정 (뷰포트 하단 넘치면 위로 뒤집기)
  • 팝업 상태머신 참여 (Va.addAutoHide, Va.hideOtherComponents)

9. 캘린더 아이콘 vs 필드 클릭

  • 캘린더 아이콘 클릭 → 팝업 열기
  • 필드 클릭 → 필드 포커스 (팝업 안 열림)
  • 필드에서 Enter → 팝업 열기
  • 필드에 타이핑 → 마스킹된 텍스트로 직접 입력 가능 (2024-12-25)

즉, 캘린더 선택과 키보드 직접 입력을 둘 다 지원합니다.


10. Va.DatePicker vs 관련 컴포넌트

컴포넌트역할

Va.DatePicker 단일 날짜 선택 (이 문서)
Va.DatePickerField DatePicker + Field 래퍼 (라벨/검증)
Va.YearPicker 년도만 선택 (바로 위 클래스 va_component.js:6624)
Va.MonthPicker 년-월 선택
Va.DateRangePicker 시작-종료 날짜 범위
Va.DateTimePicker 날짜 + 시간
Va.TimePicker 시간만

11. 팝업 상태머신 연동

프레임워크의 공용 팝업 상태머신 참여:

  • 다른 팝업(Combobox, ColorPicker 등) 열려 있으면 자동 닫고 표시
  • 외부 클릭 시 자동 닫힘
  • _hiddenRootElement = this.popElement — hidden area로 이동 가능

CLAUDE.md 6장 "민감 영역"의 팝업 상태머신 사용 컴포넌트 중 하나.


12. 언제 쓰나

DatePicker가 맞을 때

  • 생일·계약일·마감일 등 단일 날짜 입력
  • 화면 표시 포맷과 서버 저장 포맷이 다를 때
  • 캘린더 UI로 시각적으로 날짜 선택하고 싶을 때
  • min/max로 날짜 범위 제한

다른 걸 쓸 때

  • 라벨 붙은 폼 필드 → Va.DatePickerField
  • 년도만 → Va.YearPicker
  • 시작-종료 범위 → Va.DateRangePicker
  • 날짜+시간 → Va.DateTimePicker
  • 시간만 → Va.TimePicker

13. 흔한 조합 예시

// 한국 기본
{ tagName: 'datePicker', value: '20241225' }

// 서버가 하이픈 포함 원할 때
{
    tagName: 'datePicker',
    valueDateSeperator: '-',
    value: '2024-12-25'          // → 화면: 2024-12-25, 저장: 2024-12-25
}

// 미국식 표시
{
    tagName: 'datePicker',
    dateFormat: 'mdy',
    dateSeperator: '/',
    value: '20241225'            // 화면: 12/25/2024
}

// 범위 제한 (올해만)
{
    tagName: 'datePicker',
    min: '20240101',
    max: '20241231'
}

// 슬래시 구분
{
    tagName: 'datePicker',
    dateSeperator: '/',
    value: '20241225'            // 화면: 2024/12/25
}

// 오늘 이후만 (예약일)
{
    tagName: 'datePicker',
    min: new Date().toISOString().slice(0,10).replace(/-/g,'')
}

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

  1. value는 문자열 — Date 객체가 아니라 '20241225' 같은 문자열. Date 객체를 넘기면 .substring() 호출에서 크래시.
  2. setValue()가 8자리 이상 요구 — 미만이면 조용히 무시 (va_component.js:7093-7095).
  3. value.trim() 호출  setValue(null)은 안 되고 return, setValue('')는 비움 처리. 하지만 숫자 넘기면 크래시.
  4. dateFormat과 valueDateFormat 혼동 주의 — 화면 vs 저장. 각각의 seperator도 별도.
  5. getValue()는 항상 문자열 반환 — 빈 값일 땐 ''.
  6. 마스킹 자동 설정  dateFormat에 따라 masking이 자동. 사용자가 직접 masking 지정하면 덮어씀.
  7. ymd가 기본 — 옵션 미지정 시. dateFormat / valueDateFormat 둘 다.
  8. 필드에 잘못된 날짜 타이핑 가능 — 마스킹은 자릿수만 강제. 2024-99-99 같은 잘못된 날짜도 입력 가능. 검증 별도 필요.
  9. 팝업 캘린더 언어 — 요일/월 이름이 하드코딩 또는 프레임워크 언어 설정에 의존. 다국어 필요 시 Va.Lang 확인.
  10. min / max 범위 검사는 팝업 UI에만 적용 — 필드 직접 타이핑으로 범위 밖 값 넣으면 안 막힘. 별도 검증 필요.
  11. showPop()이 drawCalendar() 호출 — 별칭이 아니라 캘린더 다시 그림. 성능 주의.
  12. 팝업 상태머신 참여 — 다른 팝업과 자동 상호 배타.
  13. 가상 스크롤 없음 — 캘린더는 고정 크기.
  14. 연도 이동 UI 없음(?) — 기본 UI는 월 단위 이동. 년 단위 빠른 이동이 필요하면 YearPicker 조합.
  15. 한글 요일 표시 — 프로젝트 언어 설정 확인 필요.
  16. timezone 개념 없음 — 로컬 문자열 처리만. UTC 시각 정확도가 중요하면 별도 처리.

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

Combobox (콤보박스)  (0) 2026.09.10