Skip to content

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 선택
messagesCalendarMessages브라우저 locale 자동 (KO/JA/EN)모든 라벨. 미지정 시 navigator.language 기준 자동 선택
datenumber (ms timestamp)-single / month / year 의 v-model 값
startTime / endTimenumber (ms timestamp)-range 모드의 시작/종료 timestamp
timeZoneOffsetnumber (ms)9 * 60 * 60 * 1000표시·계산 기준 타임존 offset
minDate / maxDatenumber-선택 가능한 최소/최대 날짜
maxTimeRangenumber (ms)-range-datetime 의 최대 기간 (초과 시 [적용] 비활성)
disabledDate(d: Dayjs) => boolean-사용자 정의 disable 규칙
holidaysCalendarHoliday[]-공휴일 목록. 셀 하단 점 표식 + hover tooltip
weekStartsOn0 | 110 = 일요일, 1 = 월요일
inlinebooleanfalse테두리·그림자 제거
showFooterboolean!inlineFooter 표시 여부
autoFocusbooleanfalse마운트 즉시 root에 focus (popup 통합용, InputDate가 자동 설정)
hideMinutebooleanfalserange-datetime 에서 분 컬럼 숨김. 분은 0 으로 emit
visibleMonths1 | 212 면 듀얼 캘린더. 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

EventPayload발생 시점
update:datenumbersingle / month / year 임시 선택
update:startTimenumberrange 시작 시각 임시 변경
update:endTimenumberrange 종료 시각 임시 변경
update:selecting'start' | 'end'range-datetime 의 현재 편집 단계 (외부 인디케이터용)
apply{ startTime?, endTime?, date? }[적용] 클릭 시 확정
cancel-[취소] 또는 ESC

v-model은 임시값을 즉시 노출합니다. 명시적 확정만 받으려면 apply 만 사용하세요.

키보드

동작
/ / / day view에서 focus cursor 이동 (±1일 / ±7일). 첫 입력은 anchor(선택값 또는 오늘) 안착, 그 다음부터 실제 이동
Enterfocus된 셀 select, 또는 root focus면 primary action ([적용]/[다음])
Esc[취소] (1단계) / [이전] (range-datetime 2단계)
PageUp / PageDownprev/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 와의 연계

InputDatecalendar prop을 추가하면 드롭다운 영역이 Calendar로 대체됩니다. calendar 와 기존 프리셋 items 는 상호 배타적입니다.

Props (InputDate 추가)

Prop타입기본값설명
calendarbooleanfalsetrue면 dropdown에 Calendar만 렌더 (preset 미노출)
calendarMode'auto' | 'range-date' | 'range-datetime''auto''auto'dateFormat 으로 자동 결정
calendarMessagesCalendarMessages브라우저 locale 자동Calendar 라벨

calendarMode='auto' 매핑:

dateFormatmode듀얼 캘린더
YYYY-MM-DDrange-date (footer 없음, 2-click 즉시 적용)✓ (visibleMonths=2 자동)
YYYY-MM-DD HH / YYYY-MM-DD HH:mmrange-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"
/>