Calendar

stablev1.0.0

Dropdown date picker

Overview

Use this element in addition to an input field to display a dropdown calender from which the user will be able to choose a date in a visual way.

This element is built upon the flatpickr calendar package (maximum version v4.5.7), with a layer of CSS code on top of it to resemble the Design System style. All the calendar related JS functionality should be intact (no time slot selection has been added with the Design System). So, apart from the methods and functionalities explained below, you should be able to use whatever you find in the flatpickr documentation.

Usage

Dependencies

To get the [name of the component] component working, include the dependencies in your project in the following order:

  1. npm
  2. Sass
  3. Javascript
"design-system": "git+ssh://git@github.com/Selectra-Dev/design-system.git"
@import "/node_modules/design-system/src/sass/03-organisms/calendar";
import Calendar from 'design-system/src/js/03-organisms/calendar';

Basic code

To get the calendar element working, you need to add a .calendar__holder class to the form-group input wrapper, as it's needed for the positioning of the elements. After that, the code.cp-inline-code input element needs the usual forms classes, as well as the calendar specific calendar class. Optionally you can add an id that can be used to target this particular calendar at initialization. Finally, alongside the input element, we need to place two button elements; one to clear an already selected date and another to press and display the calendar.

  1. Pug
  2. HTML
  3. JS
.form-group.calendar__holder
  label.form-group__label(for='testdate') Label:
  .form-group__item-addon.calendar#calendarID
    input#testdate.form-group__item(type="date", data-input)
    button.flatpickr__clear-btn(type='button',data-clear)
      +icon('circle-cross-mark', '24')
    button.btn.btn--secondary.form-group__addon-btn(type='button', data-toggle)
      +icon('calendar', '24')
<div class="form-group calendar__holder">
  <label class="form-group__label" for="testdate">Label:</label>
  <div class="form-group__item-addon calendar" id="calendarID">
    <input class="form-group__item" id="testdate" type="date" data-input />
    <button class="flatpickr__clear-btn" type="button" data-clear>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-circle-cross-mark"></use>
      </svg>
    </button>
    <button class="btn btn--secondary form-group__addon-btn" type="button" data-toggle>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-calendar"></use>
      </svg>
    </button>
  </div>
</div>
Calendar( '.calendar', {}, 'fr' );

Modifiers

Add the following modifier to change the appearance of the calendar in mobile devices.

Mobile right hand

  1. Pug
  2. HTML
.form-group.calendar__holder.flatpickr--mobile-right
  label.form-group__label(for='testdate') Label:
  .form-group__item-addon.calendar#calendarID
    input#testdate.form-group__item(type="date", data-input)
    button.flatpickr__clear-btn(type='button',data-clear)
      +icon('circle-cross-mark', '24')
    button.btn.btn--secondary.form-group__addon-btn(type='button', data-toggle)
      +icon('calendar', '24')
<div class="form-group calendar__holder flatpickr--mobile-right">
  <label class="form-group__label" for="testdate">Label:</label>
  <div class="form-group__item-addon calendar" id="calendarID">
    <input class="form-group__item" id="testdate" type="date" data-input />
    <button class="flatpickr__clear-btn" type="button" data-clear>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-circle-cross-mark"></use>
      </svg>
    </button>
    <button class="btn btn--secondary form-group__addon-btn" type="button" data-toggle>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-calendar"></use>
      </svg>
    </button>
  </div>
</div>

This modifier changes the positioning of the calendar dropdown from left (default behavior) to the right, where it's more accesible in mobile devices held with the right hand.

To achieve this behavior, add the class flatpickr--mobile-right to the main form-group element.

👁 Warning
This behavior is only for mobile devices, and is not based on media queries, so even if you decrease the size of your viewport, it won't work on desktop browsers.

Mobile full-width

  1. Pug
  2. HTML
.form-group.calendar__holder.flatpickr--full-width
  label.form-group__label(for='testdate') Label:
  .form-group__item-addon.calendar#calendarID
    input#testdate.form-group__item(type="date", data-input)
    button.flatpickr__clear-btn(type='button',data-clear)
      +icon('circle-cross-mark', '24')
    button.btn.btn--secondary.form-group__addon-btn(type='button', data-toggle)
      +icon('calendar', '24')
<div class="form-group calendar__holder flatpickr--full-width">
  <label class="form-group__label" for="testdate">Label:</label>
  <div class="form-group__item-addon calendar" id="calendarID">
    <input class="form-group__item" id="testdate" type="date" data-input />
    <button class="flatpickr__clear-btn" type="button" data-clear>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-circle-cross-mark"></use>
      </svg>
    </button>
    <button class="btn btn--secondary form-group__addon-btn" type="button" data-toggle>
      <svg class="icon icon--24" aria-hidden="true">
        <use xlink:href="img/sprite.svg#icon-calendar"></use>
      </svg>
    </button>
  </div>
</div>

This modifier will force the dropdown calendar picker to occupy the full width available up until MD breakpoint.

JavaScript configuration

// JavaScript line to initialize the previously imported Calendar
Calendar(selector, options, locale)

When initializing the document via JavaScript, need to pass 3 parameters:

  • Selector: The selector of the element to initialize. Either the .calendar class, or a more specific ID to initialize individually.
  • Options: We can leave this field blank ( {} ) if we want the default options, or pass an object with the options we want to tweak.
  • Locale: We can pass either fr for French locale, or es for Spanish locale. If nothing is declared, the calendar will be displayed with the default English locale.

👁 Warning
When passing the options object, bear in mind that the following parameters should not be overwritten:prevArrow, nextArrow, appendTo, static, wrap and altInput

Minimum date

Calendar('.calendar', {
  minDate: 'today',
}, 'fr')

Use this parameter to indicate the minimum date that the user can effectively select, disabling all prior dates. If today is selected, only today and future dates can be selected.

Maximum date

Calendar('.calendar', {
  maxDate: 'today',
}, 'fr')

Use this parameter to indicate the maximum date that the user can effectively select, disabling all future dates. If today is selected, only today and past dates can be selected.

Disabled dates

// Array with disabled dates
Calendar( '.calendar', {
  'disable': [
    '2018-12-25', // Christmas Day
    '2019-01-01', // Le jour de l'an
    '2019-04-22', // Le lundi de Pâques
    '2019-05-01', // La fête du Travail
    '2019-05-08', // La victoire de 1945
    '2019-05-10', // Le jeudi de l'Ascension
    '2019-05-21', // Le lundi de Pentecôte
    '2019-07-14', // La fête nationale
    '2019-08-15', // L'Assomption
    '2019-11-01', // La Toussaint
    '2019-11-11', // L'Armistice
    '2019-12-25' // Noël
  ],
}, 'fr' );

// Function to disable sundays (first day of the week = 0 position in an array)
Calendar( '.calendar', {
  'disable': [
    function( date ) {
      return ( date.getDay() === 0 );
    }],
}, 'fr' );

To disable dates, we need to pass an array with the dates we want to disable.

Optionally, you can pass a function too, that disable certain days. The function takes a Date object, and must return a boolean value. If it's true the date will be disabled.

Alternative format

Calendar('.calendar', {
  altFormat: 'j F, Y',
}, 'fr')

To make our Design System work as a skin for the flatpickr component, we make use of the an alternative input. When initialized, the original input gets hidden, and we are only showing an alternative one, that holds the date in whichever format we want. We use this property to specify how to display that date.

Date formatting tokens
Character Description Example
d Day of the month, 2 digits with leading zeros 01 to 31
D A textual representation of a day Mon through Sun
l (lowercase 'L') A full textual representation of the day of the week Sunday through Saturday
j Day of the month without leading zeros 1 to 31
J Day of the month without leading zeros and ordinal suffix 1st, 2nd, to 31st
w Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday)
W Numeric representation of the week 0 (first week of the year) through 52 (last week of the year)
F A full textual representation of a month January through December
m Numeric representation of a month, with leading zero 01 through 12
n Numeric representation of a month, without leading zeros 1 through 12
M A short textual representation of a month Jan through Dec
U The number of seconds since the Unix Epoch 1413704993
y A two digit representation of a year 99 or 03
Y A full numeric representation of a year, 4 digits 1999 or 2003
Z ISO Date format 2017-03-04T01:23:43.000Z

Disable mobile

Calendar('.calendar', {
  disableMobile: true,
}, 'fr')

Set it to true to always use the non-native picker. By default, the component will resort to the native controller in mobile devices.

👁 Caution
If you have disabled any date, the native picker should be disabled, as there's no option to disable certain dates in the native controllers.

Allow input

Calendar('.calendar', {
  allowInput: true,
}, 'fr')

Set it to true to activate the direct input of data in the input element itself. By default the direct entry is disabled.

👁 Caution
This option should go along some kind of input masking or RegEx to force the correct input, as well as an altFormat that is easy to fill. Note that this example does not follow this practice, making the UX very cumbersome.