Date picker (TDatePicker)

VueJs reactive date-time picker component with multiple features, configurable classes and variants, and most common events. Friendly with utility-first frameworks like TailwindCSS.

SunMonTueWedThuFriSat
Value: 1987-02-18

Code for the example above:

<t-datepicker
  v-model="date"
  placeholder="Select a date"
  date-format="Y-m-d"
  user-format="m/d/Y"
/>

Props

PropertyTypeDefault valueDescription
idStringundefinedid attribute of the text input that shows the user friendly date
disabledBooleanundefineddisabled attribute of the text input that shows the user friendly date
nameStringundefinedname attribute of the hidden input that contains the formatted
readonlyBooleanundefinedreadonly attribute of the text input that shows the user friendly date
autofocusBooleanundefinedautofocus attribute of the text input that shows the user friendly date
requiredBooleanundefinedrequired attribute of the text input that shows the user friendly date
tabindex[String, Number]undefinedtabindex attribute of the text input that shows the user friendly date
value (v-model)[Date, String, Number, Array]nullThe current value of the component
placeholderStringundefinedPlaceholder for the text input that contains the user friendly date
inputNameStringundefinedName attribute for the text input that contains the user friendly date, the name prop is used for the hidden input
weekStartNumber0First day of the week show in the calendar, 0 = Sunday
monthsPerViewNumber1How many months calendar show per view (see Multiple months per view)
langStringenDefault language used in the component
localeObject{...}Object that define the localization (see Localization)
localesObject{}Object with the different languages objects available (see Formatting tokens)
dateFormatString'Y-m-d'Formatted date added to the hidden input and to the v-model value
userFormatString'F j, Y'User friendly format that is shown in the text input
dateFormatterFunctionundefinedAllows you to override the default date formatter function (see Custom date parse and format)
dateParserFunctionundefinedAllows you to override the default date parser function (see Custom date parse and format)
closeOnSelectBooleantrueIf set will close the date picker when a date is selected
showDaysForOtherMonthBooleantrueIf set will show the days for the prev/next button in the current calendar view
showBooleanfalseIf set will show the datepicker open when the component is loaded
inlineBooleanfalseIf set will show the datepicker open as a block
initialViewString'day'Initial view of the calendar (other options 'month', 'year' )
yearsPerViewNumber12How many years will show in the year view
disabledDates[Date, Array, Function, String]undefinedDisable a single date, a group or dates or based in a function (see Disable dates)
highlightDates[Date, Array, Function, String]undefinedHighlight a single date, a group or dates or based in a function (see Highlight dates)
maxDate[Date, String]undefinedMax allowed date
minDate[Date, String]undefinedMin allowed date
initialDate[Date, String]undefinedInitial active date
conjunctionString','When multiple dates or range used to join the dates values
multipleBooleanfalseWhen set it will create multiple hidden inputs with all the selected dates (see Multiple dates)
rangeBooleanfalseWhen set it will expect a range of dates to be selected (see Range)
clearableBooleantrueIf set will allow you to clear the date value

Classes and variants format

This component expects an object with classes named after every child element.

The properties in that object are the following:

PropertyDescription
wrapperWrapper for the component
inlineWrapperWrapper for the component when uses is inline
Dropdown related classes
dropdownWrapperDropdown wrapper
dropdownDropdown
enterClassTransition class
enterActiveClassTransition class
enterToClassTransition class
leaveClassTransition class
leaveActiveClassTransition class
leaveToClassTransition class
Text input related classes
inputWrapperInput wrapper
inputText input
clearButtonClear butotn
clearButtonIconClaer button icon
Picker views
viewGroupGroups all the views, for example when shows multiple months
viewA single view of the calendar
Navigator
navigatorDate navigator wrapper
navigatorViewButtonView toggler button
navigatorViewButtonIconView toggler button icon
navigatorViewButtonBackIconView toggler button back icon
navigatorViewButtonMonthView toggler month text
navigatorViewButtonYearView toggler year text
navigatorViewButtonYearRangeView toggler year range text
navigatorLabelLabel show instead of the button when have more that one month per view
navigatorLabelMonthLabel month text
navigatorLabelYearLabel year
navigatorPrevButtonNavigator prev button
navigatorNextButtonNavigator next button
navigatorPrevButtonIconNavigator prev button icon
navigatorNextButtonIconNavigator prev next icon
Calendar View
calendarWrapperCalendar wrapper
calendarHeaderWrapperCalendar header wrapper
calendarHeaderWeekDayCalendar header week day
calendarDaysWrapperCalendar days list wrapper
calendarDaysDayWrapperCalendar single day wrapper
Day item
otherMonthDayDay that is for another month
emptyDayHtml tag used as placeholder when we dont show other month days
inRangeFirstDayFirst day for ranges
inRangeLastDayLast day for ranges
inRangeDayDay inside a range
selectedDayDay selected
activeDayDay active (for keyboard navigation)
highlightedDayHighlighted day
dayDefault day
todayToday day
Months View
monthWrapperMonth list wrapper
selectedMonthSelected month
activeMonthActive month (for keyboard navigation)
monthDefault month
Years View
yearWrapperYears list wrapper
yearDefault year
selectedYearSelected year
activeYearActive year

Default fixed classes

As you may know, the fixed classes are shared and merged with the different variants and default classes. The classes we define here as default are the ones that you usually will need to make this component works correctly so you can only focus on colors, typography, etc when creating your theme.

{
  navigator: 'flex',
  navigatorViewButton: 'flex items-center',
  navigatorViewButtonIcon: 'flex-shrink-0 h-5 w-5',
  navigatorViewButtonBackIcon: 'flex-shrink-0 h-5 w-5',
  navigatorLabel: 'flex items-center py-1',
  navigatorPrevButtonIcon: 'h-6 w-6 inline-flex',
  navigatorNextButtonIcon: 'h-6 w-6 inline-flex',

  inputWrapper: 'relative',
  viewGroup: 'inline-flex',
  view: 'w-64',
  calendarDaysWrapper: 'grid grid-cols-7',
  calendarHeaderWrapper: 'grid grid-cols-7',
  monthWrapper: 'grid grid-cols-4',
  yearWrapper: 'grid grid-cols-4',

  clearButton: 'flex flex-shrink-0 items-center justify-center absolute right-0 top-0 m-2 h-6 w-6',
  clearButtonIcon: 'fill-current h-3 w-3',
};

Default classes

{
  // Dropdown related classes
  wrapper: 'inline-flex flex-col',
  dropdownWrapper: 'relative z-10',
  dropdown: 'origin-top-left absolute rounded-md shadow-lg',
  enterClass: '',
  enterActiveClass: 'transition ease-out duration-100 transform opacity-0 scale-95',
  enterToClass: 'transform opacity-100 scale-100',
  leaveClass: 'transition ease-in transform opacity-100 scale-100',
  leaveActiveClass: '',
  leaveToClass: 'transform opacity-0 scale-95 duration-75',

  // Wrapper for inline calendar
  inlineWrapper: '',

  // Text input related classes
  inputWrapper: '',
  input: 'form-input w-full',
  clearButton: 'hover:bg-gray-200 text-gray-500 rounded',
  clearButtonIcon: '',

  // Picker views
  viewGroup: 'bg-white border',
  view: '',

  // Navigator
  navigator: 'pt-2 px-2',
  navigatorViewButton: 'transition ease-in-out duration-100 inline-flex cursor-pointer rounded-full px-2 py-1 -ml-1 hover:bg-gray-200',
  navigatorViewButtonIcon: 'fill-current text-gray-500',
  navigatorViewButtonBackIcon: 'fill-current text-gray-500',
  navigatorViewButtonMonth: 'text-gray-700 font-semibold',
  navigatorViewButtonYear: 'text-gray-600 ml-1',
  navigatorViewButtonYearRange: 'text-gray-600 ml-1',
  navigatorLabel: 'py-1',
  navigatorLabelMonth: 'text-gray-700 font-semibold',
  navigatorLabelYear: 'text-gray-600 ml-1',
  navigatorPrevButton: 'transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full p-1 ml-2 ml-auto disabled:opacity-25 disabled:cursor-not-allowed',
  navigatorNextButton: 'transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 rounded-full p-1 -mr-1 disabled:opacity-25 disabled:cursor-not-allowed',
  navigatorPrevButtonIcon: 'text-gray-500',
  navigatorNextButtonIcon: 'text-gray-500',

  // Calendar View
  calendarWrapper: 'p-2',
  calendarHeaderWrapper: '',
  calendarHeaderWeekDay: 'uppercase text-xs text-gray-600 w-8 h-8 flex items-center justify-center',
  calendarDaysWrapper: '',
  calendarDaysDayWrapper: 'w-full h-8 flex flex-shrink-0 items-center',

  // Day item
  otherMonthDay: 'text-sm rounded-full w-8 h-8 mx-auto hover:bg-blue-100 text-gray-400 disabled:opacity-25 disabled:cursor-not-allowed',
  emptyDay: '',
  inRangeFirstDay: 'text-sm bg-blue-500 text-white w-full h-8 rounded-l-full',
  inRangeLastDay: 'text-sm bg-blue-500 text-white w-full h-8 rounded-r-full',
  inRangeDay: 'text-sm bg-blue-200 w-full h-8 disabled:opacity-25 disabled:cursor-not-allowed',
  selectedDay: 'text-sm rounded-full w-8 h-8 mx-auto bg-blue-500 text-white disabled:opacity-25 disabled:cursor-not-allowed',
  activeDay: 'text-sm rounded-full bg-blue-100 w-8 h-8 mx-auto disabled:opacity-25 disabled:cursor-not-allowed',
  highlightedDay: 'text-sm rounded-full bg-blue-200 w-8 h-8 mx-auto disabled:opacity-25 disabled:cursor-not-allowed',
  day: 'text-sm rounded-full w-8 h-8 mx-auto hover:bg-blue-100 disabled:opacity-25 disabled:cursor-not-allowed',
  today: 'text-sm rounded-full w-8 h-8 mx-auto hover:bg-blue-100 disabled:opacity-25 disabled:cursor-not-allowed border border-blue-500',

  // Months View
  monthWrapper: 'p-2',
  selectedMonth: 'text-sm rounded w-full h-12 mx-auto bg-blue-500 text-white',
  activeMonth: 'text-sm rounded w-full h-12 mx-auto bg-blue-100',
  month: 'text-sm rounded w-full h-12 mx-auto hover:bg-blue-100',

  // Years View
  yearWrapper: 'p-2',
  year: 'text-sm rounded w-full h-12 mx-auto hover:bg-blue-100',
  selectedYear: 'text-sm rounded w-full h-12 mx-auto bg-blue-500 text-white',
  activeYear: 'text-sm rounded w-full h-12 mx-auto bg-blue-100',

}

Events

EventArgumentsDescription
inputString (The current date formatted)Emitted every time the value of the v-model change
changeString (The current date formatted)Emitted every time the value of the v-model change
focusFocusEventEmitted when the text input inside the component is focused
blurFocusEventEmitted when the text input inside the component is blurred
keydownKeyboardEventEmitted when the user key down any key
hidden``Emitted when the dropdown is hidden
shown``Emitted when the dropdown is shown
update:showBooleanUsed to sync the show prop
activeChangeDateEmitted when the active date change
userFormatedDateStringEmitted when the user formatted date change

Scoped slots

Slotdescription
dayContent of a day button inside the calendar
monthContent of a month button inside the calendar
yearContent of a year button inside the calendar
clearButtonReplaces the SVG icon inside the button to clear the input

Day scoped slot

The day scoped slot include this information that may be useful for you when rendering the value

Propdescription
dayFormattedThe day formatted
isForAnotherMonthIf the day belongs to a different month that the one is active
isFirstDayOfRangeFor ranges: if the day is the first day of the range
isLastDayOfRangeFor ranges: if the day is the last day of the range
isInRangeFor ranges: if the day is part of the range
isSelectedIf the day is selected
isActiveIf the day is active (for keyboard navigation)
isHighlightedIf the day is highlighted
isTodayIf the day is today
dayThe Date object that represents the current
activeDateA Date object that represents the current active day
valueA Date object that represents the currently selected day

Example

Let`s show a cake when the day is in an hypothetical array of birthdays and a taco every tuesday:

<t-datepicker
  v-model="date"
  inline
>
  <template
    slot="day"
    slot-scope="{ day, dayFormatted }"
  >
    <span v-if="birthdays.includes(day)">
      šŸŽ‚
    </span>
    <span v-else-if="day.getDay() === 2">
      šŸŒ®
    </span>
    <span v-else>
      {{ dayFormatted }}
    </span>
  </template>
</t-datepicker>
SunMonTueWedThuFriSat

Month scoped slot

The month scoped slot include this information that may be useful for you when rendering the value

Propdescription
monthFormattedThe month formatted
isSelectedIf the month is selected
isActiveIf the month is active (for keyboard navigation)
monthThe Date object that represents the current month
activeDateA Date object that represents the current active month
valueA Date object that represents the currently selected month

Example

Let's show a pumpkin in October:

<t-datepicker
  v-model="date"
  initial-view="month"
  inline
>
  <template
    slot="month"
    slot-scope="{ month, monthFormatted }"
  >
    <span v-if="month.getMonth() === 9">
      šŸŽƒ
    </span>
    <span v-else>
      {{ monthFormatted }}
    </span>
  </template>
</t-datepicker>

Year scoped slot

The year scoped slot include this information that may be useful for you when rendering the value

Propdescription
yearFormattedThe year formatted
isSelectedIf the year is selected
isActiveIf the year is active (for keyboard navigation)
yearThe Date object that represents the current year
activeDateA Date object that represents the current active year
valueA Date object that represents the currently selected year

Clear icon scoped slit

Props in the clearButton slot

Propdescription
classNameOriginal clearButtonIcon class
formatedDateCurrent formatted date
userFormatedDateCurrent user formatted date
activeDateA Date object that represents the currently active date
valueA Date object that represents the currently selected date

Localization

Since the localization files of this component are based in the Flatpickr component dozens of locales are already available in the source code.

Add more locales

To keep the bundle size small only the English locale is loaded by default but adding more locales is very easy.

  1. Import the locale file from the vue-tailwind/dist/l10n/{localename} path.

  2. Add that locale object to the locale prop in the configuration settings for the TDatepicker:

import Vue from 'vue'
import VueTailwind from 'vue-tailwind'
import Spanish from 'vue-tailwind/dist/l10n/es'

const settings = {
  // TInput: {...},
  // ...,
  TDatepicker: {
    // classes: {...},
    // fixedClasses: {...},
    locale: Spanish,
  }
}

Vue.use(VueTailwind, settings)

Multiple locales

If you need multiple locales you can use the locales prop of the date-picker, when using the component you can switch the active language by using the lang prop:

  1. Import all the locale files you need from the vue-tailwind/dist/l10n/{localename} path.

  2. Add those locales to the configuration settings when installing the library:

  3. Optionally define a default language.

import Vue from 'vue'
import VueTailwind from 'vue-tailwind'

import English from 'vue-tailwind/dist/l10n/index'
import Spanish from 'vue-tailwind/dist/l10n/es'
import Mandarin from 'vue-tailwind/dist/l10n/zh'
import Japanese from 'vue-tailwind/dist/l10n/ja'
import French from 'vue-tailwind/dist/l10n/fr'

const settings = {
  // TInput: {...},
  // ...,
  TDatepicker: {
    // classes: {...},
    // fixedClasses: {...},
    locales: {
      en:  English,
      es:  Spanish,
      zh:  Mandarin,
      ja:  Japanese,
      fr:  French,
    },
    // Optionally define the default language
    lang: 'es'
  }
}

Vue.use(VueTailwind, settings)

When using the component you can switch the language by using the lang prop.

<t-datepicker lang="fr" />

Custom localization

Of you you can also define your own localization file, just use one of the ones available in the source code as a base and add it to your settings as you do with any of the imported files.

Since the custom localization files are merged to the default localization you just need to define the attributes you want to override.

Example:

import Vue from 'vue'
import VueTailwind from 'vue-tailwind'

const customLocale = {
  weekdays: {
    shorthand: ["SšŸ˜“", "MšŸ˜­", "TšŸ˜‘", "WšŸ˜¶", "TšŸ˜”", "FšŸ˜Ž", "SšŸ˜µ"],    
  },
}

const settings = {
  // TInput: {...},
  // ...,
  TDatepicker: {
    // classes: {...},
    // fixedClasses: {...},
    locale: customLocale,
  }
}

Vue.use(VueTailwind, settings)
SšŸ˜“MšŸ˜­TšŸ˜‘WšŸ˜¶TšŸ˜”FšŸ˜ŽSšŸ˜µ
Notice that in the custom locale I am only defining one of the different attributes the locale files have. These attributes will be merged with the default localization file.

Formatting tokens

Credits to the guys behind the Flatpickr from were I mostly copied the code behind this formatting feature including the table below:

Each character in the table below can be used in dateFormat and userFormat options to achieve the format you need.

Date Formatting Tokens

CharacterDescriptionExample
dDay of the month, 2 digits with leading zeros01 to 31
DA textual representation of a dayMon through Sun
l (lowercase 'L')A full textual representation of the day of the weekSunday through Saturday
jDay of the month without leading zeros1 to 31
JDay of the month without leading zeros and ordinal suffix1st, 2nd, to 31st
wNumeric representation of the day of the week0 (for Sunday) through 6 (for Saturday)
WNumeric representation of the week0 (first week of the year) through 52 (last week of the year)
FA full textual representation of a monthJanuary through December
mNumeric representation of a month, with leading zero01 through 12
nNumeric representation of a month, without leading zeros1 through 12
MA short textual representation of a monthJan through Dec
UThe number of seconds since the Unix Epoch1413704993
yA two-digit representation of a year99 or 03
YA full numeric representation of a year, 4 digits1999 or 2003
ZISO Date format2017-03-04T01:23:43.000Z

Time Formatting Tokens

CharacterDescriptionExample
HHours (24 hours)00 to 23
hHours1 to 12
GHours, 2 digits with leading zeros1 to 12
iMinutes00 to 59
SSeconds, 2 digits00 to 59
sSeconds0, 1 to 59
KAM/PMAM or PM

Escaping Formatting Tokens

You may escape formatting tokens using \\.

{
    dateFormat: "Y-m-d\\Z", // Displays: 2017-01-22Z
}

Custom date parse and format

If you want to use your own date formatter / parser you can do it by using the dateFormatter and dateParser props. You don't need to use it both, but you need to ensure that the formatted date works for the parsed date and vice versa.

Both props expect a function that receives the following parameters:

ParameterTypeDescription
dateObjDate or nullDate to be parsed or formatted
formatStringThe format defined in the props

Example

Consider the following example where we use the moment library to handle the dates:

<template>
  <t-datepicker
    v-model="date"
    :date-formatter="dateFormatter"
    :date-parser="dateParser"
    date-format="YYYY-MM-DD"
    user-format="LLLL"
  />
</template>

<script>
import moment from 'moment'

export default {
  data () {
    return {
      date: '1987-03-18'
    }
  },
  methods: {
    dateFormatter (date, format) {
      return moment(date).format(format)
    },
    dateParser (date, format) {
      return moment(date, format).toDate()
    }
  }
}
</script>
Notice in the example above that the dateFormat prop and userFormat props are now using valid moment format strings

Disable dates

You can use the disableDates props to disable one or many fixed dates or based on a function.

The props accept the following formats:

FormatTypeDescription
Date stringStringDate formatted as a string (will be parsed according to the dateFormat from)
Date objectDateYou can pass a Date object directly
FunctionFunctionA function that receives the current date that is being validated
Array of dates and methodArrayAn array that includes all the methods above

Example

For this example lets disable dates with an array with all the valid formats:

<template>
  <t-datepicker
    v-model="date"
    inline
    :disabled-dates="disabledDates"
  />
</template>

<script>
export default {
  data () {
    return {
      date: '1987-03-18',
      disabledDates: [
        // A formatted date
        '1987-03-19',
        // A date object ('1987-03-25',)
        new Date(1987, 4, 25),
        // Disable mondays
        function (date) {
          return date.getDay() === 1
        }
      ]
    }
  }

}
</script>
SunMonTueWedThuFriSat

Highlight dates

You can use the highlightDates props to highlight one or many fixed dates or based on a function.

The props accept the following formats:

FormatTypeDescription
Date stringStringDate formatted as a string (will be parsed according to the dateFormat from)
Date objectDateYou can pass a Date object directly
FunctionFunctionA function that receives the current date that is being validated
Array of dates and methodArrayAn array that includes all the methods above

Example

For this example lets hightlight dates with an array with all the valid formats:

<template>
  <t-datepicker
    v-model="date"
    inline
    :highlight-dates="highlightDates"
  />
</template>

<script>
export default {
  data () {
    return {
      date: '1987-03-18',
      highlightDates: [
        // A formatted date
        '1987-03-19',
        // A date object ('1987-03-25',)
        new Date(1987, 4, 25),
        // Disable mondays
        function (date) {
          return date.getDay() === 1
        }
      ]
    }
  }

}
</script>
SunMonTueWedThuFriSat

Handle multiple dates

The input will allow the user to select multiple dates if the v-model (or value) of the input has an array, it doesn't matter if the user set the multiple prop.

When you use the multiple prop the difference is that it will render one hidden inputs per value, this especially useful for POST form submissions.

If you set multiple to false (default value) the hidden input will contain all the dates separated by comma o whatever value set in the conjunction prop

Example

SunMonTueWedThuFriSat
[]

Ranges

The Datepicker is compatible with "range" values, when setting the value of the model will expect an array where the first element represents the "from" value, and the second one the "to" value.

Range Values

When the value of a range changes you should consider that the value is handled in three different ways:

  1. The v-model or the value of the component will be an array with 2 formatted dates.

  2. It will create a hidden input with the formatted dates separated by comma o whatever value used in the conjunction prop. If used together with the multiple prop it will create two hidden inputs with both (from and two) values.

  3. The text input will render the value with the user format and by using the rangeSeparator defined in the current localization.

Example

SunMonTueWedThuFriSat
-- to --

Multiple months per view

The Datepicker allows you to display multiple calendar per view by using the monthsPerView prop.

Example

SunMonTueWedThuFriSat
January2021
SunMonTueWedThuFriSat
February2021
SunMonTueWedThuFriSat

Timepicker

The time-picker feature will be an important feature of this component but is not ready yet. I am working hard to have it ready as soon as possible. Follow me on twitter @alfonsobries so I can keep you updated.