Skip to content

Component slots

Replace the built-in components with custom implementation

month-year

Create and use a custom component implementation in the header for month/year select

Info

When using this slot, the overlays will not be available, it is up to you to create them if you want

Warning

Depending on the used mode, slot will provide a different set of props

Exposed props:

Date picker

ts
interface DefaultSelect {
  value: number;
  text: string;
  className?: Record<string, boolean>;
}

interface Props {
    month: number; // Selected month value
    year: number; // Selected year value
    months: DefaultSelect[]; // Generated array of months
    years: DefaultSelect[]; // Generated array of years
    updateMonthYear: (month: number, year: number, fromNav: boolean) => void; // Exposed function to update month and year
    handleMonthYearChange: (isNext: boolean, fromNav?: boolean) => void; //  Exposed function to auto handle next/previous month
    instance: number; //  In case of multi-calendars, instance is the order of the calendar
}
interface DefaultSelect {
  value: number;
  text: string;
  className?: Record<string, boolean>;
}

interface Props {
    month: number; // Selected month value
    year: number; // Selected year value
    months: DefaultSelect[]; // Generated array of months
    years: DefaultSelect[]; // Generated array of years
    updateMonthYear: (month: number, year: number, fromNav: boolean) => void; // Exposed function to update month and year
    handleMonthYearChange: (isNext: boolean, fromNav?: boolean) => void; //  Exposed function to auto handle next/previous month
    instance: number; //  In case of multi-calendars, instance is the order of the calendar
}

Month picker

ts
interface Props {
  year: ComputedRef<(instance: number) => number>; // Selected year on a given instance
  months: OverlayGridItem[][]; // Groupped array of months (by 3)
  years: OverlayGridItem[][]; // Groupped array of years (by 3) 
  selectMonth: (month: number, instance: number) => void; // Exposed function to update month value
  selectYear: (year: number, instance: number) => void; // Exposed function to update year value
  instance: number; // In case of multi-calendars, instance is the order of the calendar
}
interface Props {
  year: ComputedRef<(instance: number) => number>; // Selected year on a given instance
  months: OverlayGridItem[][]; // Groupped array of months (by 3)
  years: OverlayGridItem[][]; // Groupped array of years (by 3) 
  selectMonth: (month: number, instance: number) => void; // Exposed function to update month value
  selectYear: (year: number, instance: number) => void; // Exposed function to update year value
  instance: number; // In case of multi-calendars, instance is the order of the calendar
}

Year picker

ts
interface Props {
  years: OverlayGridItem[][]; // Groupped array of months (by 3)
  selectYear: (year: number) => void; // Exposed function to update year value
}
interface Props {
  years: OverlayGridItem[][]; // Groupped array of months (by 3)
  selectYear: (year: number) => void; // Exposed function to update year value
}

Shared type

ts
interface OverlayGridItem {
  value: number; // Value in the overlay cell
  text: string; // Text displayed in the overlay cell
  active: boolean; // If the selection is active
  disabled: boolean; // If the selection is disabled
  className: Record<string, boolean>; // Applied classes on a given cell
}
interface OverlayGridItem {
  value: number; // Value in the overlay cell
  text: string; // Text displayed in the overlay cell
  active: boolean; // If the selection is active
  disabled: boolean; // If the selection is disabled
  className: Record<string, boolean>; // Applied classes on a given cell
}
Code Example
vue
<template>
    <VueDatePicker v-model="date">
      <template 
          #month-year="{
              month,
              year,
              months,
              years,
              updateMonthYear,
              handleMonthYearChange
      }">
        <div class="custom-month-year-component">
          <select 
              class="select-input"
              :value="month" 
              @change="updateMonth($event, updateMonthYear, year)">
            <option v-for="m in months" :key="m.value" :value="m.value">{{ m.text }}</option>
          </select>
          <select 
              class="select-input"
              :value="year"
              @change="updateYear($event, updateMonthYear, month)">
            <option v-for="y in years" :key="y.value" :value="y.value">{{ y.text }}</option>
          </select>
        </div>
        <div class="icons">
          <span 
              class="custom-icon" 
              @click="handleMonthYearChange(false)">
            <ChevronLeftIcon />
          </span>
          <span 
              class="custom-icon" 
              @click="handleMonthYearChange(true)">
            <ChevronRightIcon />
          </span>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref } from 'vue';

import ChevronLeftIcon from './Icons/ChevronLeftIcon.vue';
import ChevronRightIcon from './Icons/ChevronRightIcon.vue';

const date = ref(new Date());

type UpdateMonthYear = (month: number, year: number) => void;

const updateMonth = (event: InputEvent, updateMonthYear: UpdateMonthYear, year: number) => {
  updateMonthYear(+(event.target as HTMLSelectElement).value, year);
};

const updateYear = (event: InputEvent, updateMonthYear: UpdateMonthYear, month: number) => {
  updateMonthYear(month, +(event.target as HTMLSelectElement).value);
};
</script>

<style lang="scss">
.custom-month-year-component {
  display: flex;
  align-items: center;
  margin: 0 auto;
}

.select-input {
  margin: 5px 3px;
  padding: 5px;
  width: auto;
  border-radius: 4px;
  border-color: var(--dp-border-color);
  outline: none;
  -webkit-appearance: menulist;
}

.icons {
  display: flex;
  box-sizing: border-box;
}

.custom-icon {
  padding: 5px;
  display: flex;
  height: 25px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  width: 25px;
  color: var(--dp-icon-color);
  text-align: center;
  border-radius: 50%;

  svg {
    height: 20px;
    width: 20px;
  }

  &:hover {
    background: var(--dp-hover-color);
  }
}
</style>
<template>
    <VueDatePicker v-model="date">
      <template 
          #month-year="{
              month,
              year,
              months,
              years,
              updateMonthYear,
              handleMonthYearChange
      }">
        <div class="custom-month-year-component">
          <select 
              class="select-input"
              :value="month" 
              @change="updateMonth($event, updateMonthYear, year)">
            <option v-for="m in months" :key="m.value" :value="m.value">{{ m.text }}</option>
          </select>
          <select 
              class="select-input"
              :value="year"
              @change="updateYear($event, updateMonthYear, month)">
            <option v-for="y in years" :key="y.value" :value="y.value">{{ y.text }}</option>
          </select>
        </div>
        <div class="icons">
          <span 
              class="custom-icon" 
              @click="handleMonthYearChange(false)">
            <ChevronLeftIcon />
          </span>
          <span 
              class="custom-icon" 
              @click="handleMonthYearChange(true)">
            <ChevronRightIcon />
          </span>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref } from 'vue';

import ChevronLeftIcon from './Icons/ChevronLeftIcon.vue';
import ChevronRightIcon from './Icons/ChevronRightIcon.vue';

const date = ref(new Date());

type UpdateMonthYear = (month: number, year: number) => void;

const updateMonth = (event: InputEvent, updateMonthYear: UpdateMonthYear, year: number) => {
  updateMonthYear(+(event.target as HTMLSelectElement).value, year);
};

const updateYear = (event: InputEvent, updateMonthYear: UpdateMonthYear, month: number) => {
  updateMonthYear(month, +(event.target as HTMLSelectElement).value);
};
</script>

<style lang="scss">
.custom-month-year-component {
  display: flex;
  align-items: center;
  margin: 0 auto;
}

.select-input {
  margin: 5px 3px;
  padding: 5px;
  width: auto;
  border-radius: 4px;
  border-color: var(--dp-border-color);
  outline: none;
  -webkit-appearance: menulist;
}

.icons {
  display: flex;
  box-sizing: border-box;
}

.custom-icon {
  padding: 5px;
  display: flex;
  height: 25px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  width: 25px;
  color: var(--dp-icon-color);
  text-align: center;
  border-radius: 50%;

  svg {
    height: 20px;
    width: 20px;
  }

  &:hover {
    background: var(--dp-hover-color);
  }
}
</style>

time-picker

Create and use a custom component for the time picker

This slot exposes the following:

  • time (Time)
    • Reactive time object with hours, minutes and seconds
  • updateTime (UpdateTime)
    • Exposed function to update time
ts
// Array values are used if range is enabled
interface Time {
    hours: number | number[];
    minutes: number | number[];
    seconds: number | number[]
}

type UpdateTime = (value: number | number[], isHours: boolean, isSeconds: boolean) => void;
// Array values are used if range is enabled
interface Time {
    hours: number | number[];
    minutes: number | number[];
    seconds: number | number[]
}

type UpdateTime = (value: number | number[], isHours: boolean, isSeconds: boolean) => void;

Info

Keep in mind that when you are using the range picker, both values for the time must be emitted. For example if you want to update the second date hours, you will call a function something like this updateTime([firstValueSaved, newSecondValue])

Code Example
vue
<template>
    <VueDatePicker v-model="date">
      <template #time-picker="{ time, updateTime }">
        <div class="custom-time-picker-component">
          <select 
            class="select-input" 
            :value="time.hours"
            @change="updateTime(+$event.target.value)"
          >
            <option 
              v-for="h in hoursArray"
              :key="h.value"
              :value="h.value">{{ h.text }}</option>
          </select>
          <select
            class="select-input"
            :value="time.minutes"
            @change="updateTime(+$event.target.value, false)"
          >
            <option 
              v-for="m in minutesArray"
              :key="m.value"
              :value="m.value">{{ m.text }}</option>
          </select>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue';


const date = ref(new Date());

const hoursArray = computed(() => {
  const arr = [];
  for (let i = 0; i < 24; i++) {
    arr.push({ text: i < 10 ? `0${i}` : i, value: i });
  }
  return arr;
});

const minutesArray = computed(() => {
  const arr = [];
  for (let i = 0; i < 60; i++) {
    arr.push({ text: i < 10 ? `0${i}` : i, value: i });
  }
  return arr;
});

</script>

<style lang="scss">
.custom-time-picker-component {
  display: flex;
  align-items: center;
  justify-content: center;
}

.select-input {
  margin: 5px 3px;
  padding: 5px;
  width: 100px;
  border-radius: 4px;
  border-color: var(--dp-border-color);
  outline: none;
  -webkit-appearance: menulist;
}
</style>
<template>
    <VueDatePicker v-model="date">
      <template #time-picker="{ time, updateTime }">
        <div class="custom-time-picker-component">
          <select 
            class="select-input" 
            :value="time.hours"
            @change="updateTime(+$event.target.value)"
          >
            <option 
              v-for="h in hoursArray"
              :key="h.value"
              :value="h.value">{{ h.text }}</option>
          </select>
          <select
            class="select-input"
            :value="time.minutes"
            @change="updateTime(+$event.target.value, false)"
          >
            <option 
              v-for="m in minutesArray"
              :key="m.value"
              :value="m.value">{{ m.text }}</option>
          </select>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref, computed } from 'vue';


const date = ref(new Date());

const hoursArray = computed(() => {
  const arr = [];
  for (let i = 0; i < 24; i++) {
    arr.push({ text: i < 10 ? `0${i}` : i, value: i });
  }
  return arr;
});

const minutesArray = computed(() => {
  const arr = [];
  for (let i = 0; i < 60; i++) {
    arr.push({ text: i < 10 ? `0${i}` : i, value: i });
  }
  return arr;
});

</script>

<style lang="scss">
.custom-time-picker-component {
  display: flex;
  align-items: center;
  justify-content: center;
}

.select-input {
  margin: 5px 3px;
  padding: 5px;
  width: 100px;
  border-radius: 4px;
  border-color: var(--dp-border-color);
  outline: none;
  -webkit-appearance: menulist;
}
</style>

action-row

Create and use a custom component for action row

This slot exposes the following:

  • internalModelValue (Date | Date[] | null)
    • Current selected value in the datepicker
  • selectDate (() => void)
    • Select the current internalModelValue value
  • closePicker (() = void)
    • Close the datepicker menu
  • disabled (boolean)
    • If the value is invalid based on the provided configuration
Code Example
vue
<template>
    <VueDatePicker v-model="date">
      <template #action-row="{ internalModelValue, selectDate }">
        <div class="action-row">
          <p class="current-selection">{{ formatDate(internalModelValue) }}</p>
          <button class="select-button" @click="selectDate">Select Date</button>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { format } from 'date-fns'

const date = ref(new Date());

const formatDate = (date: Date) => {
  return format(date, 'dd.MM.yyyy, HH:mm');
};

</script>

<style lang="scss">
.action-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}
</style>
<template>
    <VueDatePicker v-model="date">
      <template #action-row="{ internalModelValue, selectDate }">
        <div class="action-row">
          <p class="current-selection">{{ formatDate(internalModelValue) }}</p>
          <button class="select-button" @click="selectDate">Select Date</button>
        </div>
      </template>
    </VueDatePicker>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import { format } from 'date-fns'

const date = ref(new Date());

const formatDate = (date: Date) => {
  return format(date, 'dd.MM.yyyy, HH:mm');
};

</script>

<style lang="scss">
.action-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}
</style>

Released under the MIT License.