The date range picker you've ever needed! Now, works without jQuery!

Caleran.js is a Date Range Picker plugin, coded with plain javascript and using moment.js as the manipulator, parser, validator and formatter of date/time variables. Minified 60k javascript, and 60k CSS.

Get it from CodeCanyon

Features

Date Range Picker

It's a range picker!

Predefined Ranges

You can use default ranges, or define your own!

Single Date Support

It can also be used as a single date picker!

Customizable

You can modify all the picker's behaviour like hiding some part, disabling some feature etc.

Quick Switching

Supports fast month and year navigation!

Inline Support

If you don't like dropdowns, you can convert your input to an inline calendar!

Mobile Ready

It renders beautifully on mobile devices

Portrait/Landscape Support

Also has a different landscape layout

Touch Slide Support

You can slide between months!

109 Languages

We support them all!
(What moment.js supports :P)

Sass Support

You can re-design completely using SASS.

Grunt Tasks

Yes, it's the automation era.

Icons (except Sass and Grunt logo) made by Freepik from www.flaticon.com is licensed by CC 3.0 BY

How to use it

The main files of this plugin are caleran.min.js and caleran.min.css, which are generated by compiling and minifying caleran.js and caleran.css. The plugin relies on moment.js libraries, so it needs to be included before including caleran.min.js.

The font used on this plugin is Roboto, and the icons are provided by Font Awesome which are included remotely from their CDN's. You can change it anyway you want.

The example configuration which can be found in the base index file is:

<link
  href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,500,700"
  rel="stylesheet"
/>
<link
  href="http://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
  rel="stylesheet"
/>

<!-- .caleran includes -->
<link href="build/css/caleran.min.css" rel="stylesheet" />
<script src="build/js/moment.min.js"></script>
<script src="build/js/caleran.min.js"></script>
<!-- .end caleran includes -->

Then, to attach a caleran object to an element you desire, use this:

caleran(".caleran");

You can customize your plugin with options you provide to the initializing function,

caleran(".caleran", { inline: true, startOnMonday: true });

or the element's data-plugin-options property.

<input
  class="caleran"
  data-plugin-options='{"calendarCount":1,"showHeader":true,"showFooter":true}'
  name="calendar-input"
  type="text"
  value="08.08.2020 - 08.09.2020"
/>

Once initalized, you can access the caleran object like this:

var caleran = document.querySelector(".caleran").caleran;
caleran.config.startDate = new Date();
caleran.reDrawCalendars();

Properties

Once you've got the caleran instance object, you can access these properties:

elem


Type: DOM Element

Description: The HTML DOM Element which the instance is created on.

Please Note that if you've chosen a different target element, you will be accessing the initiator element by calling caleran.elem. Your actual target element would be caleran.config.target.

config


Type: JS Object

Description: The instance's configuration object. Consists of merging default values and user defined settings. The details of it is explained in the Configuration section.



These properties are also defined, but not recommended to tinker on.

container


Type: DOM Element

Description: This refers to the outermost container element of the instance dropdown or inline instance and the input itself.


Type: DOM Element

Description: This refers to the header part of the plugin.


Type: DOM Element

Description: This refers to the footer part, - not the mobile buttons part - the ranges part of the plugin.

input


Type: DOM Element

Description: This refers to the first child of the container, which contains everything except the input which is caleran instantiated on.



For example,

var caleran = caleran("#elem1");
// caleran.elem will be equal to document.getElementById("elem1") or document.querySelector("#elem1");




Configuration

These are the options you can set with the javascript plugin initialization object, or with the data-plugin-options html attribute on the input element, or within the events by directly modifying the caleran.config object.

startDate


Type: MomentJS Object | javascript Date Object | string

Default: null

Description: the selected start date, initially today is selected if not defined inside the input's value, or any of the initialization configuration methods.

endDate


Type: MomentJS Object | javascript Date Object | string

Default: null

Description: The selected end date, initially today is selected if not defined inside the input's value, or any of the initialization configuration methods.

format


Type: string

Default: "L"

Description: The default format for showing in input, defaults to short date format of locale, for all possible inputs, look here: https://momentjs.com/docs/#/displaying/format/ default: 'L'

dateSeparator


Type: string

Default: " - "

Description: if not used as a single date picker, this will be the seperator, default " - ".

calendarCount


Type: integer

Default: 2

Description: how many calendars will be shown in the plugin screen, default 2

inline


Type: boolean

Default: false

Description: display as an inline input replacement instead of input dropdown. default: false

minDate


Type: MomentJS Object | javascript Date Object | string | null

Default: null

Description: minimum selectable date, default null (no minimum)

maxDate


Type: MomentJS Object | javascript Date Object | string | null

Default: null

Description: maximum selectable date, default null (no maximum)

hideOutOfRange


Type: boolean

Default: false

Description: hides the arrows which navigates out of the range defined with min and max dates, default false

showHeader


Type: boolean

Default: true

Description: visibility of the part which displays the selected start and end dates, default true

showFooter


Type: boolean

Default: true

Description: visibility of the part which contains user defined ranges, default true

startEmpty


Type: boolean

Default: false

Description: whether the input should remain empty until user makes a selection, default false

showButtons


Type: boolean

Default: false

Description: whether the input should display the apply and cancel buttons in dropdown, default false

enableSwipe


Type: boolean

Default: true

Description: whether the input should be responsive to mobile swipe action, default true

enableKeyboard


Type: boolean

Default: true

Description: enable this if you want to add keyboard support to the calendar. The keys are:

  • UP : Go to same weekday on the previous week
  • DOWN : Go to same weekday on the next week
  • LEFT : Go to the previous day
  • RIGHT : Go to the next day
  • PG UP : Go to the previous month
  • PG DOWN : Go to the next month
  • SHIFT + PG UP : Go to the previous year
  • SHIFT + PG DOWN : Go to the next year

startOnMonday


Type: boolean

Default: false

Description: If you want to start the calendars on Monday, set this to true. Note that if the locale already starts on Monday, this setting will be ignored.

container


Type: string

Default: "body"

Description: the selector of the dropdowns container.

oneCalendarWidth


Type: integer

Default: 230

Description: The width of one calendar, if two calendars are shown, the input width will be 2 * this setting.

showOn


Type: "bottom"|"top"|"left"|"right"|"center"

Default: "bottom"

Description: dropdown placement position relative to input element, will be adjusted to the viewport.

arrowOn


Type: "bottom"|"top"|"left"|"right"|"center"

Default: "left"

Description: arrow position relative to dropdown element, will be adjusted to the viewport.

autoAlign


Type: boolean

Default: true

Description: Enables dropdown auto placement change when the dropdown is not fully visible on the viewport.

locale


Type: string

Default: null

Description: moment locale setting, for more information: https://momentjs.com/docs/#/i18n/changing-locale/, and for a list of available locales: https://momentjs.com/ (bottom of the page)

singleDate


Type: boolean

Default: false

Description: If you want a single date picker, set this to true, default false

target


Type: DOM Element

Default: null

Description: The element to update after selection, if it's null, the element that is instantiated on will be updated.

ranges


Type: Array

Default: Predefined ranges range objects array

Description: An array of objects which each will create a button in the footer, and when the user clicks, it'll automatically will be applied. One range is defined like below:

Prototype:

{
  title: "1 Week",                    // [string] : The label which will appear on the button
  startDate: moment(),                // [MomentJS Object | javascript Date Object | string] : the first date of the range
  endDate: moment().add(6, "days")    // [MomentJS Object | javascript Date Object | string] : the last date of the range
}

rangeLabel


Type: string

Default: "Ranges: "

Description: The title displayed in the defined ranges list section, default "Ranges: "

cancelLabel


Type: string

Default: "Cancel"

Description: The cancel button label, default "Cancel"

applyLabel


Type: string

Default: "Apply"

Description: The apply button label, default "Apply"

enableMonthSwitcher


Type: boolean

Default: true

Description: Enables the month switcher when clicking on month names. Default: true

enableYearSwitcher


Type: boolean

Default: true

Description: Enables the year switcher when clicking on years. Default: true

numericMonthSwitcher


Type: boolean

Default: false

Description: If set to true, shows month numbers instead of month names in month selector. Default: false

monthSwitcherFormat


Type: string

Default: "MMMM" (long month name format)

Description: Changes the format of the month name displayed on the month selector. Default: "MMMM" (long month name format)

showWeekNumbers


Type: boolean

Default: false

Description: Shows week numbers on the left of the calendars. Default: false

autoCloseOnSelect


Type: boolean

Default: false

Description: On instances that are not displayed inline, this setting is used to automatically close the dropdown when a selection is made.

disableDays


Type: function

Description: Enables day based disabling filters, input value is the current day to be processed. Example:

Prototype:

  {
    disableDays: function(day){
       return day.isSame(moment("17/05/2020")); // will return true on that day and the day will be disabled.
    }
  }

disabledRanges


Type: Array of Objects

Default: []

Description: Enables user to disable specific ranges from selection. Can be used with continuous option to preserve continuity.

Prototype:

[
  {
    start: [MomentJS Object],
    end: [MomentJS Object]
  },
  ..
]

disableOnlyStart


Type: boolean

Default: false

Description: When set, the disabled ranges only affect the start date selection. End dates are not limited to the active days. Default: false

disableOnlyEnd


Type: boolean

Default: false

Description: When set, the disabled ranges only affect the end date selection. Start dates are not limited to the active days. Default: false

minSelectedDays


Type: integer

Default: 0

Description: Defines the minimum selection duration. For example, if set to 1, the same day ranges won't be accepted. Another example, if set to 3, at least 3 days should be selected. Default: 0

isHotelBooking


Type: boolean

Default: false

Description: Enables the hotel booking mode. Disabled range start and end dates are half disabled, so a start date can be another range's end date, and a end date can be another range's start date. Useful for check-in check-out selections for hotel systems. Default: false

DOBCalendar


Type: boolean

Default: false

Description: Enables the date-of-birth selection mode. Shows the year selector when opened, then the month selector, then the day selector.Not available in inline mode, Switches the calendar to single date selection when enabled.

continuous


Type: boolean

Default: false

Description: Adds a check if the selected range continues any disabled days. Reverts the selection to it's original state when the user tries to select a range which contains a disabled date.

rangeOrientation


Type: string

Default: "horizontal"

Description: Sets the range view to "vertical" or "horizontal" which renders the range part on the right or on the bottom of the calendar. Default: "horizontal"

verticalRangeWidth


Type: integer

Default: 150

Description: Sets the vertical range view panel width in pixels.

nextMonthIcon


Type: string

Default: <i class='fa fa-arrow-right'></i>

Description: Sets the icon of the next month arrow, default: <i class='fa fa-arrow-right'></i></i>,

prevMonthIcon


Type: string

Default: <i class='fa fa-arrow-left'></i>

Description:Sets the icon of the previous month arrow

rangeIcon


Type: string

Default: <i class='fa fa-retweet'></i>

Description:Sets the icon of the range label

headerSeparator


Type: string

Default: <i class='fa fa-chevron-right'></i>

Description:Sets the icon between the header dates

Available Events

onbeforeselect


Event which is triggered before selecting the end date ( a range selection is completed). The return value decides whether the selection will happen. Returning false will prevent the input to update.

Prototype:

  onbeforeselect: function(caleran, startDate, endDate){
    // caleran: caleran object instance
    // startDate: moment.js instance
    // endDate: moment.js instance
    return true; // false prevents update
  }



onafterselect


Event which is triggered after selecting the end date ( the input value changed )

Prototype:

  onafterselect: function(caleran, startDate, endDate){
    // caleran: caleran object instance
    // startDate: moment.js instance
    // endDate: moment.js instance
  }



onbeforeshow


Event which is triggered before showing the dropdown

Prototype:

  onbeforeshow: function(caleran){
    // caleran: caleran object instance
  }



onbeforehide


Event which is triggered before hiding the dropdown

Prototype:

  onbeforehide: function(caleran){
    // caleran: caleran object instance
  }



onaftershow


Event which is triggered after showing the dropdown

Prototype:

  onaftershow: function(caleran){
    // caleran: caleran object instance
  }



onafterhide


Event which is triggered after hiding the dropdown

Prototype:

  onafterhide: function(caleran){
    // caleran: caleran object instance
  }



onfirstselect


Event which is triggered after selecting the first date of ranges

Prototype:

  onfirstselect: function(caleran, startDate){
    // caleran: caleran object instance
    // startDate: moment.js instance
  }



onrangeselect


Event which is triggered after selecting a range from the defined range links

Prototype:

  onrangeselect: function(caleran, range){
    // caleran: caleran object instance
    // range: selected range definition
  }



onbeforemonthchange


Event which fires before changing the first calendar month of multiple calendars, or the month of a single calendar. The return value decides whether the month switch will take place.

Prototype:

  onbeforemonthchange: function(caleran, month, direction){
    // caleran: caleran object instance
    // month : moment.js object of first day of the month selected on the **first** calendar
        // direction: "next" or "prev", shows the month change direction. if `month.month()` is 4,
        // and direction is "prev", next month will be 3.
    return true; // false disables switching
  }



onaftermonthchange


Event which fires after changing the first calendar month of multiple calendars, or the month of a single calendar

Prototype:

  onaftermonthchange: function(caleran, month){
    // caleran: caleran object instance
    // month : moment.js object of first day of the month selected on the first calendar
  }



onafteryearchange


Event which fires after changing the year of the calendars with the year selector

Prototype:

  onafteryearchange: function(caleran, year){
    // caleran: caleran object instance
    // year : moment.js object of first day of the year selected on the first calendar
  }



ondraw


Event which fires after redraws in calendar

Prototype:

  onredraw: function(caleran){
    // caleran: caleran object instance
  }



onBeforeInit


Event which fires just before the instance initialization happens

Prototype:

  onBeforeInit: function(caleran){
  // caleran: caleran object instance
  }



onBeforeDestroy


Event which fires just before the instance destruction happens, can be returned false to cancel the destruction.

Prototype:

  oninit: function(caleran){
    // caleran: caleran object instance
  }



oninit


Event which fires after instance initialization

Prototype:

  oninit: function(caleran){
    // caleran: caleran object instance
  }



ondestroy


Event which fires after instance destruction

Prototype:

  oninit: function(caleran){
    // caleran: caleran object instance
  }



oncancel


Event which fires after the user clicks the cancel button, cancellation can be prevented by returning false

Prototype:

  oncancel: function(caleran, start, end){
    // caleran: caleran object instance
    // start: selected start date
    // end: selected end date
    return true;
  }



validateClick


Event which fires when an user clicks a day, can be prevented by returning false

Prototype:

  validateClick: function(cellmoment){
    // cellmoment: clicked cell's date
    return true;
  }

Methods

validateDates


Validates the startDate, endDate, minDate, maxDate parameters of the instance configuration, by the means of parsability and order, and defaults to today's date for startDate and endDate, and to null for maxDate and minDate.

clearInput


Clears the input.

fetchInputs


Retrieves the date(s) from the instance holder input and validates them before putting it to it's configuration.

updateInput


Updates the instance holder input with the instance values and configuration.

drawNextMonth


Triggers the instance show the next month after the first calendar month as the first calendar.

drawPrevMonth


Triggers the instance show the previous month before the first calendar month as the first calendar.

reDrawCalendars


Triggers a complete restructuring of the instance. Drawing the container first, then the header, then the calendars, then the footer.

reDrawCells


Only modifies the calendar's related parts with the configuration variables. Doesn't entirely build the instance again like reDrawCalendars method does.

setViewport


On dropdown instances, if the dropdown falls outside of the viewport (when shown, not scrolled) this function decides and calculates it's new position opposed to its configuration. For example, if the dropdown position is set to bottom and it falls below the page bottom edge, this method makes it appear as it was set to top for once.

showDropdown


On dropdown and mobile instances, if the dropdown is not visible, this method triggers the show method.

hideDropdown


On dropdown and mobile instances, if the dropdown is visible, this method hides it.

setStart


Sets the start date of the input. Time portion is ignored.

setEnd


Sets the end date of the input. Time portion is ignored.

setMinDate


Sets the minimum selectable date of the input. Time portion is ignored.

setMaxDate


Sets the maximum selectable date of the input. Time portion is ignored.

setDisplayDate


Sets the displayed month and year, day and hours are ignored.

var instance = document.querySelector(".caleran").caleran;

// using MomentJS Object
instance.setStart(moment());

// using javascript Date object
instance.setStart(new Date());

// using ISO and RFC standardized date strings
instance.setStart("2020-11-27T13:07:04+00:00"); // ISO 8601 and RFC 3339
instance.setStart("Mon, 27 Nov 2020 13:07:04 +0000"); // RFC 822, 1035, 1123, 2822
instance.setStart("Monday, 27-Nov-17 13:07:04 UTC"); // RFC 2822

// using unix timestamp
instance.setStart(1511788024);

// using custom formatted date time string
instance.setStart(moment("16:06 27.11.2020", "HH:mm dd.MM.YYYY"));

Examples

Default Range Picker


Preview:

HTML:

<input type="text" id="caleran-ex-1" />

JavaScript:

<script type="text/javascript">caleran("#caleran-ex-1");</script>

Preview:

HTML:

<input type="text" id="caleran-ex-1-1" />
<input type="text" id="caleran-ex-1-2" />
<input type="text" id="caleran-ex-1-3" />
<input type="text" id="caleran-ex-1-4" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-1-1", {showOn:"top",autoAlign:true});
        caleran("#caleran-ex-1-2", {showOn:"left",autoAlign:true});
        caleran("#caleran-ex-1-3", {showOn:"right",autoAlign:true});
        caleran("#caleran-ex-1-4", {showOn:"bottom",autoAlign:true});
    </script>

Preview:

HTML:

<input type="text" id="caleran-ex-1-5" />
<input type="text" id="caleran-ex-1-6" />
<input type="text" id="caleran-ex-1-7" />
<input type="text" id="caleran-ex-1-8" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-1-5", {showOn:"top",autoAlign:false});
        caleran("#caleran-ex-1-6", {showOn:"left",autoAlign:false});
        caleran("#caleran-ex-1-7", {showOn:"right",autoAlign:false});
        caleran("#caleran-ex-1-8", {showOn:"bottom",autoAlign:false});
    </script>

Arrow Positioning


Preview:











HTML:

  <style>
    /** For the input layout, we included some hidden inputs */
  .vhide { visibility: hidden; }
  </style>
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-t-r" value="03/13/2020" />
  <input type="text" id="caleran-ex-t-c" value="03/13/2020" />
  <input type="text" id="caleran-ex-t-l" value="03/13/2020" />
  <input type="text" class="vhide" /><br /><br />
  <input type="text" id="caleran-ex-l-t" value="03/13/2020" />
  <input type="text" class="vhide" />
  <input type="text" class="vhide" />
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-r-t" value="03/13/2020" /><br /><br />
  <input type="text" id="caleran-ex-l-c" value="03/13/2020" />
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-c-c" value="03/13/2020" />
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-r-c" value="03/13/2020" /><br /><br />
  <input type="text" id="caleran-ex-l-b" value="03/13/2020" />
  <input type="text" class="vhide" />
  <input type="text" class="vhide" />
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-r-b" value="03/13/2020" /><br /><br />
  <input type="text" class="vhide" />
  <input type="text" id="caleran-ex-b-r" value="03/13/2020" />
  <input type="text" id="caleran-ex-b-c" value="03/13/2020" />
  <input type="text" id="caleran-ex-b-l" value="03/13/2020" />
  <input type="text" class="vhide" /><br /><br />

JavaScript:

<script type="text/javascript">
  caleran("#caleran-ex-t-r", {
      showOn: "top",
      arrowOn: "right"
  });
  caleran("#caleran-ex-t-c", {
      showOn: "top",
      arrowOn: "center"
  });
  caleran("#caleran-ex-t-l", {
      showOn: "top",
      arrowOn: "left"
  });
  caleran("#caleran-ex-l-c", {
      showOn: "left",
      arrowOn: "center"
  });
  caleran("#caleran-ex-l-t", {
      showOn: "left",
      arrowOn: "top"
  });
  caleran("#caleran-ex-l-b", {
      showOn: "left",
      arrowOn: "bottom"
  });
  caleran("#caleran-ex-c-c", {
      showOn: "center",
      arrowOn: "center"
  });
  caleran("#caleran-ex-r-c", {
      showOn: "right",
      arrowOn: "center"
  });
  caleran("#caleran-ex-r-t", {
      showOn: "right",
      arrowOn: "top"
  });
  caleran("#caleran-ex-r-b", {
      showOn: "right",
      arrowOn: "bottom"
  });

  caleran("#caleran-ex-b-r", {
      showOn: "bottom",
      arrowOn: "right"
  });
  caleran("#caleran-ex-b-c", {
      showOn: "bottom",
      arrowOn: "center"
  });
  caleran("#caleran-ex-b-l", {
      showOn: "bottom",
      arrowOn: "left"
  });
</script>

Hiding the header


Preview:

HTML:

<input type="text" id="caleran-ex-2" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-2", {showHeader: false});
    </script>

Preview:

HTML:

<input type="text" id="caleran-ex-3" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-3", {showFooter: false});
    </script>

Showing dropdown apply/cancel buttons


This will only work with dropdown desktop view, inline views don't support cancel and apply buttons. Mobile modal view already has them.
Preview:

HTML:

<input type="text" id="caleran-ex-5-3" placeholder="Select a Date" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-5-3", {showButtons: true});
    </script>

Changing calendar count


Preview:

HTML:

<input type="text" id="caleran-ex-4" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-4", {calendarCount: 3});
    </script>

Inline calendar


Preview:

HTML:

<input type="text" id="caleran-ex-5" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-5", {inline: true});
    </script>

Empty on initialization


Preview:

HTML:

<input type="text" id="caleran-ex-5-1" placeholder="Select a date" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-5-1", {startEmpty: true});
    </script>

Single date picker


Preview:

HTML:

<input type="text" id="caleran-ex-6" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-6", {singleDate: true});
    </script>

Range/Single switch


Preview:

HTML:

<label for="single-caleran-mod">
  <input
    type="radio"
    value="single"
    id="single-caleran-mod"
    name="caleran-type-selector"
    class="caleran-type-selector"
  />
  &nbsp;Single Date
</label>
<label for="multi-caleran-mod">
  <input
    type="radio"
    value="multi"
    id="multi-caleran-mod"
    name="caleran-type-selector"
    class="caleran-type-selector"
    checked
  />
  &nbsp;Multiple Dates
</label>
<input type="text" id="caleran-ex-6-4" />

JavaScript:

<script type="text/javascript">
  document.querySelectorAll(".caleran-type-selector").forEach(element => {
    element.addEventListener("click", function(){
      if(document.querySelector("#caleran-ex-6-4").caleran){
        document.querySelector("#caleran-ex-6-4").caleran.destroy();
      }
      caleran("#caleran-ex-6-4", {
        singleDate: document.querySelector(".caleran-type-selector:checked").value == "single" ? true : false
      });
    });
  });
  document.querySelector(".caleran-type-selector[value='multi']").click();
</script>

Linked Single Date Pickers


Preview:

Start Date:
End Date:

HTML:

<div style="display: flex;">
  <div>Start Date: <input type="text" id="caleran-ex-6-5-start" /></div>
  <div style="margin-left:20px;">
    End Date: <input type="text" id="caleran-ex-6-5-end" />
  </div>
</div>

JavaScript:

<script type="text/javascript">
  var startDate, endDate, startInstance, endInstance;
  var fillInputs = function () {
      startInstance.elem.value = startDate ? startDate.locale(startInstance.config.format).format(startInstance.config.format) : "";
      endInstance.elem.value = endDate ? endDate.locale(endInstance.config.format).format(endInstance.config.format) : "";
  };
  caleran("#caleran-ex-6-5-start", {
      startEmpty: document.querySelector("#caleran-ex-6-5-start").value === "",
      startDate: document.querySelector("#caleran-ex-6-5-start").value,
      endDate: document.querySelector("#caleran-ex-6-5-end").value,
      enableKeyboard: false,
      oninit: function (instance) {
          startInstance = instance;
          if (!instance.config.startEmpty && instance.config.startDate) {
              instance.elem.value = instance.config.startDate.locale(instance.config.format).format(instance.config.format);
              startDate = instance.config.startDate.clone();
          }
      },
      onbeforeshow: function (instance) {
          if (startDate) {
              startInstance.config.startDate = startDate;
              endInstance.config.startDate = startDate;
          }
          if (endDate) {
              startInstance.config.endDate = endDate.clone();
              endInstance.config.endDate = endDate.clone();
          }
          fillInputs();
          instance.updateHeader();
          instance.reDrawCells();
      },
      onfirstselect: function (instance, start) {
          startDate = start.clone();
          startInstance.globals.startSelected = false;
          startInstance.hideDropdown();
          endInstance.showDropdown();
          endInstance.config.minDate = startDate.clone();
          endInstance.config.startDate = startDate.clone();
          endInstance.config.endDate = null;
          endInstance.globals.startSelected = true;
          endInstance.globals.endSelected = false;
          endInstance.globals.firstValueSelected = true;
          endInstance.setDisplayDate(start);
          if (endDate && startDate.isAfter(endDate)) {
              endInstance.globals.endDate = endDate.clone();
          }
          endInstance.updateHeader();
          endInstance.reDrawCells();
          fillInputs();
      }
  });
  caleran("#caleran-ex-6-5-end", {
      startEmpty: document.querySelector("#caleran-ex-6-5-end").value === "",
      startDate: document.querySelector("#caleran-ex-6-5-start").value,
      endDate: document.querySelector("#caleran-ex-6-5-end").value,
      enableKeyboard: false,
      autoCloseOnSelect: true,
      oninit: function (instance) {
          endInstance = instance;
          if (!instance.config.startEmpty && instance.config.endDate) {
              instance.elem.value = (instance.config.endDate.locale(instance.config.format).format(instance.config.format));
              endDate = instance.config.endDate.clone();
          }
      },
      onbeforeshow: function (instance) {
          if (startDate) {
              startInstance.config.startDate = startDate;
              endInstance.config.startDate = startDate;
          }
          if (endDate) {
              startInstance.config.endDate = endDate.clone();
              endInstance.config.endDate = endDate.clone();
          }
          fillInputs();
          instance.updateHeader();
          instance.reDrawCells();
      },
      onafterselect: function (instance, start, end) {
          startDate = start.clone();
          endDate = end.clone();
          endInstance.hideDropdown();
          startInstance.config.endDate = endDate.clone();
          startInstance.globals.firstValueSelected = true;
          fillInputs();
          endInstance.globals.startSelected = true;
          endInstance.globals.endSelected = false;
      }
  });
</script>

Minimal Single date picker


Preview:

HTML:

<input type="text" id="caleran-ex-6-2" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-6-2", {
      singleDate: true,
      calendarCount: 1,
      showHeader: false,
      showFooter: false,
      autoCloseOnSelect: true
    });
  </script>

Ranges on the Right


Preview:

HTML:

<input type="text" id="caleran-ex-6-6-1" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-6-6-1", {
      rangeOrientation: "vertical"
    });
  </script>

Ranges on the Right with Buttons


Preview:

HTML:

<input type="text" id="caleran-ex-6-6-2" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-6-6-2", {
      rangeOrientation: "vertical",
      showButtons: true
    });
  </script>

Ranges on the Right (inline)


Preview:

HTML:

<input type="text" id="caleran-ex-6-6-3" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-6-6-3", {
      inline: true,
      rangeOrientation: "vertical"
    });
  </script>

Showing week numbers


Preview:

HTML:

<input type="text" id="caleran-ex-6-6-4" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-6-6-4", {
      showWeekNumbers: true
    });
  </script>

Auto Close on Select


Preview:

HTML:

<input type="text" id="caleran-ex-6-1" />

JavaScript:

<script type="text/javascript">
  caleran("#caleran-ex-6-1", {autoCloseOnSelect: true});
</script>

Defining Min/Max Dates


Preview:

HTML:

<input type="text" id="caleran-ex-6-3" />

JavaScript:

<script type="text/javascript">
  caleran("#caleran-ex-6-3", {
    minDate: moment().subtract(1, "weeks").startOf("week"),
    maxDate: moment().add(1, "weeks").endOf("week")
  });
</script>

Defining custom ranges


Preview:

HTML:

<input type="text" id="caleran-ex-7" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-7", {ranges: [
            {
                title: "Next Week",
                startDate: moment().add(1,"weeks").startOf("week"),
                endDate: moment().add(1,"weeks").endOf("week")
            },
            {
                title: "Today",
                startDate: moment(),
                endDate: moment()
            },
            {
                title: "Yesterday",
                startDate: moment().subtract(1,"days"),
                endDate: moment().subtract(1,"days")
            },
            {
                title: "Last 7 days",
                startDate: moment().subtract(7,"days"),
                endDate: moment().subtract(1,"days")
            },
            {
                title: "Last 30 days",
                startDate: moment().subtract(30,"days"),
                endDate: moment().subtract(1,"days")
            },
            {
                title: "This month",
                startDate: moment().startOf("month"),
                endDate: moment().endOf("month")
            },
            {
                title: "Last month",
                startDate: moment().subtract(1,"months").startOf("month"),
                endDate: moment().subtract(1,"months").endOf("month")
            }
        ]});
    </script>

Custom events


Preview:

HTML:

<input type="text" id="caleran-ex-8" />
<div class="caleranlabel"></div>

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-8", {
            onafterselect: function(caleran, startDate, endDate) {
                caleran.elem.closest(".well").querySelector(".caleranlabel")
                  .innerText = "You have chosen between " + startDate.format('LLLL') + " and " + endDate.format('LLLL');
            }
        });
    </script>

Hotel Booking System


Preview:

HTML:

<input type="text" id="caleran-ex-9-1" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-9", {
      isHotelBooking: true,
      continuous: true,
      startEmpty: true,
      minSelectedDays: 1,
      disabledRanges: [
        {
          start: moment(),
          end: moment().add(2, "days")
        }
      ]
    });
    </script>

Change first day of week


Preview:

HTML:

<input type="text" id="caleran-ex-9" />

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-9", {startOnMonday: true});
    </script>

Changing locale


Preview:

HTML:

<input type="text" id="caleran-ex-10" />

JavaScript:

    <script type="text/javascript">
        var userLanguage = navigator.language || navigator.userLanguage;
        if(userLanguage == "en") userLanguage = "fr";
        caleran("#caleran-ex-10", {locale: userLanguage });
    </script>

Changing locale (inline)


Preview:

HTML:

<input type="text" id="caleran-ex-10-2" />

JavaScript:

    <script type="text/javascript">
        var userLanguage = navigator.language || navigator.userLanguage;
        if(userLanguage == "en") userLanguage = "fr";
        caleran("#caleran-ex-10-2", {locale: userLanguage, inline: true });
    </script>

Date Of Birth (DOB) Select Mode


Preview:

HTML:

<input type="text" id="caleran-ex-10-4" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-10-4", {
      DOBCalendar: true,
      startEmpty: true
    });
  </script>

Changing locale (non-latin)


Preview:

HTML:

      <input type="text" id="caleran-ex-10-3" />

JavaScript:

      <script type="text/javascript">
          caleran("#caleran-ex-10-3", {locale: "ar", inline: true });
      </script>

RTL Support


Preview:

HTML:

      <div dir="rtl">
        <input type="text" id="caleran-ex-10-5" />
      </div>

JavaScript:

      <script type="text/javascript">
          caleran("#caleran-ex-10-5", {locale: "ar" });
      </script>

Week Select Mode


Preview:

HTML:

<input type="text" id="caleran-ex-10-1" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-10", {
      onfirstselect: function(instance, start){
        instance.config.startDate = moment(start).startOf("week");
        instance.config.endDate = moment(start).endOf("week");
        instance.globals.endSelected = true;
        instance.globals.startSelected = false;
        instance.globals.hoverDate = null;
        if(instance.input.querySelector( ".caleran-apply" )) {
          instance.input.querySelector( ".caleran-apply" ).removeAttribute( "disabled" );
        }
        instance.updateInput();
      }
    });
  </script>

Custom target element


Preview:

HTML:

<input type="text" id="caleran-ex-11-target" />
<button id="caleran-ex-11">Open caleran</button>

JavaScript:

    <script type="text/javascript">
        caleran("#caleran-ex-11", {target: document.querySelector("#caleran-ex-11-target")});
    </script>

Custom disabled ranges (with callback)


Note: This task would only fill the input on Wednesdays, because the only valid (selectable) dates are Wednesdays on the calendar. If the start day or end day isn't selectable, the plugin will revert itself to startEmpty state when initialized.

Preview:

HTML:

<input type="text" id="caleran-ex-13" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13", {
      disableDays: function(day){
        return day.day() != 3;
      }
    });
  </script>

Custom disabled ranges (with array)


Preview:

HTML:

<input type="text" id="caleran-ex-13-2" value="03/19/2020 - 03/20/2020" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-2", {
      disabledRanges: [
        {
          "start": moment("10/03/2020","DD/MM/YYYY"),
          "end": moment("18/03/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("01/04/2020","DD/MM/YYYY"),
          "end": moment("05/04/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("11/04/2020","DD/MM/YYYY"),
          "end": moment("15/04/2020", "DD/MM/YYYY")
        }
      ]
    });
  </script>

Custom disabled ranges (preserve continuousity)


Preview:

HTML:

<input type="text" id="caleran-ex-13-3" value="03/19/2020 - 03/20/2020" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-3", {
      continuous: true,
      disabledRanges: [
        {
          start: moment("10/03/2020","DD/MM/YYYY"),
          end: moment("18/03/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("01/04/2020","DD/MM/YYYY"),
          "end": moment("05/04/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("11/04/2020","DD/MM/YYYY"),
          "end": moment("15/04/2020", "DD/MM/YYYY")
        }
      ]
    });
  </script>

Disable only start dates


Preview:

HTML:

<input type="text" id="caleran-ex-13-5" value="03/19/2020 - 03/20/2020" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-5", {
      disableOnlyStart: true,
      disabledRanges: [
        {
          "start": moment("10/03/2020","DD/MM/YYYY"),
          "end": moment("18/03/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("01/04/2020","DD/MM/YYYY"),
          "end": moment("05/04/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("11/04/2020","DD/MM/YYYY"),
          "end": moment("15/04/2020", "DD/MM/YYYY")
        }
      ]
    });
  </script>

Disable only end dates


Preview:

HTML:

<input type="text" id="caleran-ex-13-6" value="03/19/2020 - 03/20/2020" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-6", {
      disableOnlyEnd: true,
      disabledRanges: [
        {
          "start": moment("10/03/2020","DD/MM/YYYY"),
          "end": moment("18/03/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("01/04/2020","DD/MM/YYYY"),
          "end": moment("05/04/2020", "DD/MM/YYYY")
        },
        {
          "start": moment("11/04/2020","DD/MM/YYYY"),
          "end": moment("15/04/2020", "DD/MM/YYYY")
        }
      ]
    });
  </script>

Show & Hide with triggers


Preview:

HTML:

<input type="text" id="caleran-ex-13-1" />
<button class="caleran-show">Show Instance</button>
<button class="caleran-hide">Hide Instance</button>

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-1");
    document.querySelector(".caleran-show").addEventListener("click",function(e){
      var caleran = document.querySelector("#caleran-ex-13-1").caleran;
      caleran.showDropdown(e);
    });
    document.querySelector(".caleran-hide").addEventListener("click",function(e){
      var caleran = document.querySelector("#caleran-ex-13-1").caleran;
      caleran.hideDropdown(e);
    });
  </script>

Using inside a modal


Preview:

HTML:

<!-- Modal -->
<div
  class="modal fade"
  id="myModal"
  tabindex="-1"
  role="dialog"
  aria-labelledby="myModalLabel"
>
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <input type="text" id="caleran-ex-12" />
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">
          Close
        </button>
      </div>
    </div>
  </div>
</div>
<!-- Button trigger modal -->
<button
  type="button"
  class="btn btn-primary"
  onclick="$('#myModal').modal('show');"
>
  Launch demo modal
</button>

JavaScript:

<script type="text/javascript">caleran("#caleran-ex-12");</script>

Hiding the arrows on unavailable months


Preview:

HTML:

<input type="text" id="caleran-ex-13-4" value="03/19/2020 - 03/20/2020" />

JavaScript:

  <script type="text/javascript">
    caleran("#caleran-ex-13-4", {
      minDate: moment().startOf("year"),
      maxDate: moment().endOf("year"),
      startDate: moment(),
      endDate: moment(),
      hideOutOfRange: true
    });
  </script>

Important Notes

  • I left the caleran object fully accessible to the inner variables, so you can alter the object's config in any event. For example, you can alter the max date of the calendar after first selection like this (limiting the user to select max 7 days of the first selection):
onfirstselect: function(caleran, startDate){
    caleran.config.maxDate = startDate.clone().add(7,"days");
},
onafterselect: function(caleran, startDate, endDate){
    caleran.config.maxDate = null;
}

or another example, disabling previous date selection:

onfirstselect: function(caleran, startDate){
    caleran.config.minDate = startDate.clone();
},
onafterselect: function(caleran, startDate, endDate){
    caleran.config.minDate = null;
}
  • The cloning is very important when adding or subtracting, because they modify the reference element too! As you can see in the above examples, the startDate and the endDate elements are cloned when defining the maxDate and minDate values. If you don't want to modify the startDate or endDate intentionally, use cloning.

  • Only one event can be bound using the initialize config object. Multiple events are not supported.

Changelog

  • v1.0.0

    • Released initial version.
  • v1.0.1

    • Fix swipe month switch direction
    • Fix mobile calendar height limit calculation
    • Fix input focus on dropdown open
    • Add better swipe detection
  • v1.0.2