Skip to content
On this page

Components

Customize the datepicker with your custom components

WARNING

Make sure to properly read the documentation and check the examples on how to pass and configure a custom component. Wrong implementation may result in errors

TIP

You can use css variables inside custom components if you need to style for the theme

monthYearComponent

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

The component will receive the following props:

  • months: { value: number; text: string }[] -> value: 0-11, text: name of the month
  • years: { value: number; text: string }[] -> generated array of years based on provided range, text and value are the same
  • filters: filters prop
  • monthPicker: monthPicker prop
  • month: number -> This is the value of the selected month
  • year : number -> This is the value of the selected year
  • customProps: Record<string, unknown> -> Your custom props
  • instance: number -> In case you are using multiCalendars prop, it will be 1 or 2
  • minDate: Date | string -> minDate prop
  • maxDate: Date | string -> maxDate prop

Important

To update the month and the year value make sure to emit the following:

emit('update-month-year', { instance: 0;, month: number; year: number })

  • instance - if you use multiple calendars, you might switch this, by default use 0 for single calendar
    • Type: number
  • month - selected month, in case of year selection, pass month from the prop
    • Type: number
  • year - selected year, in case of month selection, pass year from the prop
    • Type: number
Code Example
vue
<template>
    <Datepicker v-model="date" :month-year-component="monthYear" />
</template>

<script>
    import { computed, ref, defineAsyncComponent } from 'vue';
    
    // Lazy load the component we want to pass
    const MonthYear = defineAsyncComponent(() => import('./MonthYearCustom.vue'));
    
    export default {
          setup() {
            const date = ref();
            
            // Return from computed as it is imported
            const monthYear = computed(() => MonthYear);
    
            return {
              date,
              monthYear
            }
          }
    }
</script>
vue
<template>
  <div class="month-year-wrapper">
    <div class="custom-month-year-component">
      <select 
            class="select-input"
            :value="month" 
            @change="updateMonth">
        <option 
            v-for="m in months" 
            :key="m.value"
            :value="m.value">{{ m.text }}</option>
      </select>
      <select 
            class="select-input" 
            :value="year" 
            @change="updateYear">
        <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="onPrev"><ChevronLeftIcon /></span>
      <span class="custom-icon" @click="onNext"><ChevronRightIcon /></span>
    </div>
  </div>
</template>

<script>
// Icons used in the example, you can use your custom ones
import ChevronLeftIcon from './ChevronLeftIcon.vue';
import ChevronRightIcon from './ChevronRightIcon.vue';

import { defineComponent } from 'vue';

export default defineComponent({
  components: { ChevronLeftIcon, ChevronRightIcon },
  emits: ['update-month-year'],
  // Available props
  props: {
    months: { type: Array, default: () => [] },
    years: { type: Array, default: () => [] },
    filters: { type: Object, default: null },
    monthPicker: { type: Boolean, default: false },
    month: { type: Number, default: 0 },
    year: { type: Number, default: 0 },
    customProps: { type: Object, default: null }
  },
  setup(props, { emit }) {
    const updateMonthYear = (month, year) => {
      emit('update-month-year', { instance: 0, month, year });
    };

    const onNext = () => {
      let month = props.month;
      let year = props.year;
      if (props.month === 11) {
        month = 0;
        year = props.year + 1;
      } else {
        month += 1;
      }
      updateMonthYear(month, year);
    };

    const onPrev = () => {
      let month = props.month;
      let year = props.year;
      if (props.month === 0) {
        month = 11;
        year = props.year - 1;
      } else {
        month -= 1;
      }
      updateMonthYear(month, year);
    };

    const updateYear = (event) => {
      updateMonthYear(props.month, +event.target.value);
    };

    const updateMonth = (event) => {
      updateMonthYear(+event.target.value, props.year);
    };

    return {
      onNext,
      onPrev,
      updateYear,
      updateMonth,
    };
  },
});
</script>

<style lang="scss">
.month-year-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
}
.custom-month-year-component {
  display: flex;
  align-items: center;
  justify-content: flex-start;
}

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

.icons {
  display: flex;
}

.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>

timePickerComponent

Create and use a custom component for the time picker

The component will receive the following props:

Note: hours and minutes values will be arrays if range picker mode is active.

Important

To update the hours and the minutes values make sure to emit the following:

  • Hours
    • Event: update:hours
    • Value: number | [number, number]
  • Minutes
    • Event: update:minutes
    • Value: number | [number, number]

Note: 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 emit something like this emit('update:hours', [firstValueSaved, newSecondValue])

Code Example
vue
<template>
    <Datepicker v-model="date" :time-picker-component="timePicker" />
</template>

<script>
    import { computed, ref, defineAsyncComponent } from 'vue';
    
    // Lazy load the component we want to pass
    const TimePicker = defineAsyncComponent(() => import('./TimePickerCustom.vue'));
    
    export default {
        setup() {
            const date = ref();
        
            // Return from computed as it is imported
            const timePicker = computed(() => TimePicker);

            return {
              date,
              timePicker 
            }
        }
    }
</script>
vue
<template>
    <div class="custom-time-picker-component">
        <select 
              class="select-input"
              :value="hours"
              @change="$emit('update:hours', +$event.target.value)">
            <option 
              v-for="h in hoursArray"
              :key="h.value"
              :value="h.value">{{ h.text }}</option>
        </select>
        <select 
              class="select-input" 
              :value="minutes"
              @change="$emit('update:minutes', +$event.target.value)">
            <option 
              v-for="m in minutesArray" 
              :key="m.value" 
              :value="m.value">{{ m.text }}</option>
        </select>
    </div>
</template>

<script>
    import { computed, defineComponent } from 'vue';

    export default defineComponent({
        emits: ['update:hours', 'update:minutes'],
        props: {
            hoursIncrement: { type: [Number, String], default: 1 },
            minutesIncrement: { type: [Number, String], default: 1 },
            is24: { type: Boolean, default: true },
            hoursGridIncrement: { type: [String, Number], default: 1 },
            minutesGridIncrement: { type: [String, Number], default: 5 },
            range: { type: Boolean, default: false },
            filters: { type: Object, default: () => ({}) },
            minTime: { type: Object, default: () => ({}) },
            maxTime: { type: Object, default: () => ({}) },
            timePicker: { type: Boolean, default: false },
            hours: { type: [Number, Array], default: 0 },
            minutes: { type: [Number, Array], default: 0 },
            customProps: { type: Object, default: null }
        },
        setup() {
            // Generate array of hours
            const hoursArray = computed(() => {
                const arr = [];
                for (let i = 0; i < 24; i++) {
                    arr.push({ text: i < 10 ? `0${i}` : i, value: i });
                }
                return arr;
            });

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

            return {
                hoursArray,
                minutesArray,
            };
        },
    });
</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;
    }
</style>

actionRowComponent

Create and use a custom component for action row

The component will receive the following props:

Info

Two events are available from this component to emit:

  • selectDate: Selects the current selection
  • closePicker: Closes the datepicker menu
Code Example
vue
<template>
    <Datepicker v-model="date" :action-row-component="actionRow" />
</template>

<script>
    import { computed, ref, defineAsyncComponent } from 'vue';
    
    // Lazy load the component we want to pass
    const ActionRow = defineAsyncComponent(() => import('./ActionRowCustom.vue'));
    
    export default {
        setup() {
            const date = ref();
        
            // Return from computed as it is imported
            const actionRow = computed(() => ActionRow);

            return {
              date,
              actionRow 
            }
        }
    }
</script>
vue
<template>
    <div class="custom-action-row">
        <p class="current-selection">{{ date }}</p>
        <button class="select-button" @click="$emit('selectDate')">Select Date</button>
    </div>
</template>

<script>
    import { computed, defineComponent } from 'vue';

    export default defineComponent({
        emits: ['selectDate', 'closePicker'],
        props: {
            selectText: { type: String, default: 'Select' },
            cancelText: { type: String, default: 'Cancel' },
            internalModelValue: { type: [Date, Array], default: null },
            range: { type: Boolean, default: false },
            previewFormat: {
                type: [String, Function],
                default: () => '',
            },
            monthPicker: { type: Boolean, default: false },
            timePicker: { type: Boolean, default: false },
        },
        setup(props) {
            const date = computed(() => {
                if (props.internalModelValue) {
                    const date = props.internalModelValue.getDate();
                    const month = props.internalModelValue.getMonth() + 1;
                    const year = props.internalModelValue.getFullYear();
                    const hours = props.internalModelValue.getHours();
                    const minutes = props.internalModelValue.getMinutes();

                    return `${month}/${date}/${year}, ${hours}:${minutes}`;
                }
                return '';
            });

            return {
                date,
            };
        },
    });
</script>

<style lang="scss">
    .custom-action-row {
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
    }

    .current-selection {
        margin: 10px 0 0 0;
    }

    .select-button {
        display: block;
        background: transparent;
        border: 1px solid var(--dp-success-color);
        color: var(--dp-success-color);
        border-radius: 4px;
        padding: 5px;
        margin: 10px;
        cursor: pointer;
    }
</style>

customProps

If you use a custom component you can pass your custom props from the datepicker via this prop

  • Type: Record<string, unknown>
  • Default: null

Also, you can use the provide function and provide needed props from the parent component

Code Example
vue
<template>
  <Datepicker :customProps="customProps" v-model="date" />
</template>

<script>
import { ref, reactive } from 'vue';

export default {
    setup() {
        const date = ref();
        // We can access this object in our custom components
        const customProps = reactive({
          foo: 'bar',
          hello: 'hi'
        });
        
        return {
            date,
            customProps,
        }
    }
}
</script>

Released under the MIT License.