Appearance
Calendar
Calendar는 달력 UI로 날짜 또는 기간을 선택하는 컴포넌트입니다. 단일 날짜, 날짜 기간, 시간을 포함한 기간 등 3가지 mode를 지원하며, 단독으로 사용하거나 InputDate의 옵션으로 함께 사용할 수 있습니다.
Mode
single — 단일 날짜 선택
한 개의 날짜를 선택합니다. 헤더의 년/월 클릭으로 year/month grid 빠른 픽커로 전환됩니다.
월화수목금토일
vue
<calendar mode="single" v-model:date="singleDate" />range-date — 기간 선택 (날짜만)
두 번 클릭으로 시작/종료를 선택합니다. 시작만 선택된 상태에서 hover 시 in-range 미리보기가 표시되고, 두 번째 클릭이 첫 번째보다 이전 날짜면 자동 swap됩니다.
월화수목금토일
vue
<calendar
mode="range-date"
v-model:start-time="rangeStart"
v-model:end-time="rangeEnd"
/>visibleMonths=2 — 듀얼 캘린더
좌·우 두 달을 동시에 렌더해 월 경계를 넘는 기간 선택을 한 화면에서 처리합니다. range-date + viewMode='day' 에서만 적용되고, 어느 화살표를 눌러도 두 패널이 함께 ±1월 이동합니다.
월화수목금토일
월화수목금토일
vue
<calendar
mode="range-date"
:visible-months="2"
v-model:start-time="dualRangeStart"
v-model:end-time="dualRangeEnd"
/>range-datetime — 기간 선택 (날짜 + 시간)
좌측 day grid + 우측 시·분 컬럼이 함께 표시되며, 시작 → 종료 2단계로 선택합니다. [다음] 으로 종료 단계 진입, [이전] 으로 복귀, [적용] 으로 commit. ESC는 1단계에선 [취소], 2단계에선 [이전] 과 동일.
월화수목금토일
:
vue
<calendar
mode="range-datetime"
v-model:start-time="dtStart"
v-model:end-time="dtEnd"
/>hideMinute — 시(hour) 단위만
hideMinute 를 켜면 분 컬럼·segment가 사라지고 분은 항상 0 으로 emit됩니다. InputDate에서 dateFormat='YYYY-MM-DD HH' 일 때 자동으로 전달됩니다.
월화수목금토일
vue
<calendar mode="range-datetime" hide-minute ... />month / year — 단일 월·연도 선택
월 그리드(4×3) 또는 연도 그리드(4×3, 12년 단위 페이지)만 렌더되어 단일 값을 선택합니다.
vue
<calendar mode="month" v-model:date="month" />
<calendar mode="year" v-model:date="year" />Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
mode | 'single' | 'range-date' | 'range-datetime' | 'month' | 'year' | - | (필수) Mode 선택 |
messages | CalendarMessages | 브라우저 locale 자동 (KO/JA/EN) | 모든 라벨. 미지정 시 navigator.language 기준 자동 선택 |
date | number (ms timestamp) | - | single / month / year 의 v-model 값 |
startTime / endTime | number (ms timestamp) | - | range 모드의 시작/종료 timestamp |
timeZoneOffset | number (ms) | 9 * 60 * 60 * 1000 | 표시·계산 기준 타임존 offset |
minDate / maxDate | number | - | 선택 가능한 최소/최대 날짜 |
maxTimeRange | number (ms) | - | range-datetime 의 최대 기간 (초과 시 [적용] 비활성) |
disabledDate | (d: Dayjs) => boolean | - | 사용자 정의 disable 규칙 |
holidays | CalendarHoliday[] | - | 공휴일 목록. 셀 하단 점 표식 + hover tooltip |
weekStartsOn | 0 | 1 | 1 | 0 = 일요일, 1 = 월요일 |
inline | boolean | false | 테두리·그림자 제거 |
showFooter | boolean | !inline | Footer 표시 여부 |
autoFocus | boolean | false | 마운트 즉시 root에 focus (popup 통합용, InputDate가 자동 설정) |
hideMinute | boolean | false | range-datetime 에서 분 컬럼 숨김. 분은 0 으로 emit |
visibleMonths | 1 | 2 | 1 | 2 면 듀얼 캘린더. range-date + day view 에서만 적용 |
CalendarMessages
ts
interface CalendarMessages {
today: string;
cancel: string;
apply: string;
next: string;
previous: string; // range-datetime 2단계의 [이전] 라벨
weekdays: [string, string, string, string, string, string, string]; // 일~토
months: [string, string, string, string, string, string, string, string, string, string, string, string];
formatYearMonth: (year: number, monthLabel: string) => string;
formatYear: (year: number) => string;
formatYearRange: (startYear: number, endYear: number) => string;
}라이브러리는 KO/JA/EN 사전 번역을 export합니다. messages 를 생략하면 navigator.language 기준 자동 선택, 명시적으로 고정하려면 상수를 import해서 전달하세요.
ts
import {
Calendar,
CALENDAR_MESSAGES_KO,
CALENDAR_MESSAGES_JA,
CALENDAR_MESSAGES_EN,
} from '@jennifersoft/vue-components-v2';vue-i18n과 함께 쓰는 경우:
vue
<script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
const { locale } = useI18n();
const messages = computed(() => {
if (locale.value === 'ja') return CALENDAR_MESSAGES_JA;
if (locale.value === 'en') return CALENDAR_MESSAGES_EN;
return CALENDAR_MESSAGES_KO;
});
</script>
<template>
<calendar mode="single" :messages="messages" />
</template>Emits
| Event | Payload | 발생 시점 |
|---|---|---|
update:date | number | single / month / year 임시 선택 |
update:startTime | number | range 시작 시각 임시 변경 |
update:endTime | number | range 종료 시각 임시 변경 |
update:selecting | 'start' | 'end' | range-datetime 의 현재 편집 단계 (외부 인디케이터용) |
apply | { startTime?, endTime?, date? } | [적용] 클릭 시 확정 |
cancel | - | [취소] 또는 ESC |
v-model은 임시값을 즉시 노출합니다. 명시적 확정만 받으려면 apply 만 사용하세요.
키보드
| 키 | 동작 |
|---|---|
← / → / ↑ / ↓ | day view에서 focus cursor 이동 (±1일 / ±7일). 첫 입력은 anchor(선택값 또는 오늘) 안착, 그 다음부터 실제 이동 |
Enter | focus된 셀 select, 또는 root focus면 primary action ([적용]/[다음]) |
Esc | [취소] (1단계) / [이전] (range-datetime 2단계) |
PageUp / PageDown | prev/next 페이지 (day=±1월, month=±1년, year=±10년) |
Tab | 시·분 input과 footer 버튼 사이 native 이동. 컬럼 cell은 tabindex=-1 이라 순회 제외 |
시·분 input focus 시 ↑/↓ 로 ±1 cyclic bump, ←/→ 로 시 ↔ 분 segment 이동.
공휴일
holidays prop으로 공휴일 목록을 넘기면 셀에 빨간 텍스트 + 하단 dot 표식 + hover tooltip이 추가됩니다. holidays 가 주어지면 한국식 주말 색상(일=빨강, 토=파랑)도 자동 활성. 공휴일은 연도·국가별로 달라서 라이브러리에 내장하지 않고 consumer가 직접 주입합니다.
ts
interface CalendarHoliday {
date: number; // ms timestamp (날짜만 매칭, 시·분·초 무시)
name?: string; // tooltip 라벨
}월화수목금토일
ts
const KOREA_HOLIDAYS_2026 = [
{ date: new Date(2026, 0, 1).getTime(), name: '신정' },
{ date: new Date(2026, 1, 16).getTime(), name: '설날 연휴' },
// ... 연속된 연휴는 각 일자를 별도 항목으로 나열
];InputDate 와의 연계
InputDate 에 calendar prop을 추가하면 드롭다운 영역이 Calendar로 대체됩니다. calendar 와 기존 프리셋 items 는 상호 배타적입니다.
Props (InputDate 추가)
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
calendar | boolean | false | true면 dropdown에 Calendar만 렌더 (preset 미노출) |
calendarMode | 'auto' | 'range-date' | 'range-datetime' | 'auto' | 'auto' 는 dateFormat 으로 자동 결정 |
calendarMessages | CalendarMessages | 브라우저 locale 자동 | Calendar 라벨 |
calendarMode='auto' 매핑:
dateFormat | mode | 듀얼 캘린더 |
|---|---|---|
YYYY-MM-DD | range-date (footer 없음, 2-click 즉시 적용) | ✓ (visibleMonths=2 자동) |
YYYY-MM-DD HH / YYYY-MM-DD HH:mm | range-datetime (footer 있음, [적용] 까지 대기) | — |
range-datetime 모드에서는 popup 열림 동안 input 텍스트의 시작 / 종료 datetime 부분 아래에 primary 색 underline이 표시되어 현재 어느 단계를 편집 중인지 시각적으로 알려줍니다.
range-date — YYYY-MM-DD
1w
vue
<input-date
v-model:start-time="startTime"
v-model:end-time="endTime"
date-format="YYYY-MM-DD"
:calendar="true"
/>range-datetime — YYYY-MM-DD HH:mm
1h
vue
<input-date
v-model:start-time="startTime"
v-model:end-time="endTime"
date-format="YYYY-MM-DD HH:mm"
:calendar="true"
/>