DatepickerTabs

A versatile date picker with day and month selection modes, multiple selection support, and various formatting options.

Great for booking systems! If users don't have a specific date in mind, they can easily pick a few different dates, a whole month, or even several months at once

First demo (click it):

View on GitHub
Navigation:
DatepickerTabs Screenshot DatepickerTabs Screenshot

Few Months Selection or certain date Demo with tabs

This example demonstrates the month selection mode with multiple month selection enabled and restriction to 3 month at once, and possibility to select certain date in other tab, with the initialization of preselected values and the month tab active by default.

Few Months Picker or date picker in both mode:

Selected Values:

Code Example:

//Few Months picker initialization
const monthPicker = new DatepickerTabs('#month-input', {
    mode: 'month',
    multipleMonths: true,
    maxMonthSelection: 3,
    monthFormat: 'MMM YYYY'
});

To show selected value in the "Selected Values:" section here in this example - use this "onDateChange" parameter to constructor.


// This code below is used to show selection in "Selected Values:" section, so you probably won't need it
onDateChange: function(dates) {
    const monthResult = document.getElementById('month-result');
    if (dates) {
        monthResult.textContent = monthPicker.getDatesAsString(dates)
    } else {
        monthResult.textContent = 'No months selected';
    }
}

Month only Mode

This example demonstrates the one month selection mode with NO date selection.

Single Month Picker Only

Selected Month:

Code Example

//Single Month mode picker only
const monthPickerOnly = new DatepickerTabs('#month-mode-example', {
    mode: 'month',
    displayType: 'month',
    multipleMonths: false,
    monthFormat: 'MMM YYYY',
});

Day only Mode

This example demonstrates the day selection mode with single date selection.

Single Day Picker Only

Selected Date:

Code Example

//Single day mode picker only
const dayPickerOnly = new DatepickerTabs('#day-mode-example', {
    displayType: 'day',
    dateFormat: 'DD MMM YYYY',
    multipleMonths: false,
});

Disabled Days Demo

Check out the latest features: Week starting on Monday, disabled days of week, and disabled specific dates.

Business Day Picker

This example has weeks starting on Monday, weekends disabled, and holidays disabled.

Selected Business Day:

Code Example

//Business Day Picker
const businessDayPicker = new DatepickerTabs('#business-day-input', {
    startWeekOnMonday: true,         // Week starts on Monday
    disabledDaysOfWeek: [0, 6],      // Disable Sunday (0) and Saturday (6)
    disabledDates: [
        '25/12/2025',                // Christmas Day
        '01/01/2025',                // New Year's Day
        '04/07/2025'                 // Independence Day
    ],
    dateFormat: 'DD/MM/YYYY'
});

Configurator

Configure your DatepickerTabs with the options below, test it out, and generate code to use in your project.

Options

Basic Configuration

Selection Options

Date Range

Disable Options

Format Options

UI Settings

Preview

Selected Value(s):

Generated Code


                

Bottom of Page Test

This tests that the date picker correctly positions itself when near the bottom of the viewport. (scroll that way so input is in the botton of the page)

DatepickerTabs Documentation

A versatile date picker with day and month selection modes, multiple selection support, and various formatting options. Ideal for booking systems where users might want to select specific dates, a whole month, or even several months at once.

Installation

Clone or download option

Clone or download the package from GitHub. Include CSS and JavaScript files in your HTML:

git clone https://github.com/swayoleg/datepicker-tabs.git
<link rel="stylesheet" href="dist/css/datepicker-tabs.min.css">
<script src="dist/js/datepicker-tabs.min.js"></script>

JSDelivr option

Alternatively, you can use JSDelivr

With a specific version (1.0.4 in this example):

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/swayoleg/datepicker-tabs@1.0.4/dist/css/datepicker-tabs.min.css">
<script src="https://cdn.jsdelivr.net/gh/swayoleg/datepicker-tabs@1.0.4/dist/js/datepicker-tabs.min.js"></script>

Or with the latest develop version:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/swayoleg/datepicker-tabs@develop/dist/css/datepicker-tabs.min.css">
<script src="https://cdn.jsdelivr.net/gh/swayoleg/datepicker-tabs@develop/dist/js/datepicker-tabs.min.js"></script>

UNPKG option

<link rel="stylesheet" href="https://unpkg.com/datepicker-tabs@latest/dist/css/datepicker-tabs.min.css">
<script src="https://unpkg.com/datepicker-tabs@latest/dist/js/datepicker-tabs.min.js"></script>

Via NPM

npm install datepicker-tabs

Basic Usage

Initialize the date picker on an input element:

// Initialize on a single input with ID
const picker = new DatepickerTabs('#date-input');

// Initialize on multiple inputs with class
const pickers = new DatepickerTabs('.date-input-class');

Options

You can customize the date picker by passing an options object:

const picker = new DatepickerTabs('#date-input', {
    // Basic configuration
    mode: 'month',                   // 'day' or 'month' mode
    displayType: 'tabs',             // Display as 'tabs', 'day', or 'month'

    // Selection options
    multipleDays: false,             // Allow multiple day selection
    multipleMonths: true,            // Allow multiple month selection
    maxMonthSelection: 6,            // Max selectable months (when multipleMonths=true)

    // Date range options
    startDate: null,                 // Initial selected date
    minDate: null,                   // Minimum selectable date
    maxDate: new Date(2026, 11, 31), // Maximum selectable date
    futureSaturdaysOnly: true,       // Only enable future Saturdays in day mode

    startWeekOnMonday: false,         // Start weeks on Monday instead of Sunday
    disabledDaysOfWeek: [0, 6],      // Disable days of week (0=Sunday, 6=Saturday)
    disabledDates: [                 // Disable specific dates
        '25/12/2025',                // Christmas Day
        new Date(2025, 0, 1)         // New Year's Day (also accepts Date objects)
    ],

    // Localization
    monthNames: ['January', 'February'], // Custom month names (shorthand provided for example)
    dayNames: ['Sun', 'Mon'],            // Custom day names (shorthand provided for example)
    dateFormat: 'DD/MM/YYYY',            // Date display format
    monthFormat: 'MMM YYYY',             // Month display format

    // UI settings
    position: 'bottom',              // 'bottom' or 'top' position
    zIndex: 9999,                    // Picker z-index

    // Persistence
    cookieName: 'datepickerTabsMode',// Cookie name for mode storage

    // Year offset settings
    backwardsYearsOffset: 5,         // How many years to show before current year
    forwardsYearsOffset: 5,          // How many years to show after current year

    // Callbacks
    onDateChange: function(date) {   // Date selection callback
        console.log('Selected date:', date);
    },

    // Container customization
    containerId: '', // Custom container ID to render calendar (if not provided, one will be generated)
});

Available Options

Date Formatting

The date picker supports the following tokens for date formatting:

Examples:

DD MMM YYYY = 01 Jan 2025
DD/MM/YYYY  = 01/01/2025
MM/DD/YYYY  = 01/01/2025
YYYY-MM-DD  = 2025-01-01

Methods

setDate(date)
Sets the selected date(s)
date: Date object, array of Date objects, or null
// Set a single date
picker.setDate(new Date());

// Set multiple dates
picker.setMultipleDays(true);
picker.setDate([new Date(2023, 0, 1), new Date(2023, 1, 1)]);

// Clear selection
picker.setDate(null);
getDate()
Gets the currently selected date(s)
const selectedDate = picker.getDate();
setMode(mode)
Sets the picker mode ('day' or 'month'). Basically which tab to show active.
mode: 'day' or 'month'
picker.setMode('month');
getMode()
Get the current tab mode show (which tab is active)
picker.getMode();
setDisplayType(type)
Sets the display type ('tabs', 'day', or 'month'). When day or month - no tabs are shown. Only one of the two tabs mode.
type: 'tabs', 'day', or 'month'
picker.setDisplayType('day');
setMultipleDays(enable)
Enables or disables multiple days selection
enable: boolean
picker.setMultipleDays(true);
setMultipleMonths(enable)
Enables or disables multiple months selection
enable: boolean
picker.setMultipleMonths(true);
setDateFormat(format)
Sets the date format for day mode
format: string (e.g., 'YYYY-MM-DD')
picker.setDateFormat('YYYY-MM-DD');
setMonthFormat(format)
Sets the date format for month mode
format: string (e.g., 'MM/YYYY')
picker.setMonthFormat('MM/YYYY');
setMinDate(date)
Sets the minimum selectable date
date: Date object or null
picker.setMinDate(new Date(2023, 0, 1));
setMaxDate(date)
Sets the maximum selectable date
date: Date object or null
picker.setMaxDate(new Date(2024, 11, 31));
setMaxMonthSelection(limit)
Sets the maximum number of months that can be selected when multiple selection is enabled
limit: number
picker.setMaxMonthSelection(3);
show()
Shows the date picker
picker.show();
hide()
Hides the date picker
picker.hide();
destroy()
Destroys the date picker instance and cleans up resources
picker.destroy();

Events

The date picker fires the following custom events:

You can listen for these events on the element where the date picker is initialized:

document.getElementById('date-input').addEventListener('datepickerApply', function(e) {
  console.log('Applied date(s):', e.detail);
});

Examples

Basic Date Picker

const datePicker = new DatepickerTabs('#date-input');

Month Picker with Multiple Selection and maximum 3 months, with tabs to date select as well

const monthPicker = new DatepickerTabs('#month-input', {
  mode: 'month',
  multipleMonths: true,
  maxMonthSelection: 3
});

Date Picker with Constraints

const constrainedPicker = new DatepickerTabs('#date-input', {
  minDate: new Date(2023, 0, 1),
  maxDate: new Date(2023, 11, 31),
  dateFormat: 'YYYY-MM-DD'
});

Pick just one month

const monthOnlyPicker = new DatepickerTabs('#month-only-picker', {
  mode: 'month',
  displayType: 'month',
  multipleMonths: false,
  monthFormat: 'MMM YYYY',
});

Saturday-Only Picker for Events

const saturdayPicker = new DatepickerTabs('#event-date', {
  futureSaturdaysOnly: true,
  dateFormat: 'DD/MM/YYYY'
});

Business Day Picker (Weekdays Only)

const businessDayPicker = new DatepickerTabs('#business-date', {
  startWeekOnMonday: true,         // Week starts on Monday
  disabledDaysOfWeek: [0, 6],      // Disable Sunday (0) and Saturday (6)
  disabledDates: [
    '2025-12-25',                  // Christmas (in YYYY-MM-DD format)
    '2025-01-01',                  // New Year's Day
    new Date(2025, 6, 4)           // Independence Day (also works with Date objects)
  ],
  dateFormat: 'YYYY-MM-DD'
});

Best Practices

To ensure smooth integration and optimal user experience, follow these best practices:

Future work

  • Add language pre-built support with i18n
  • Add start of the week with Monday option ✅ Added
  • Add disable dates array ✅ Added
  • Add disable days of week ✅ Added
  • Add tests with jest ✅ Added

Testing

DatepickerTabs includes a comprehensive test suite to ensure functionality works as expected. There are multiple ways to test the library components.

Testing in Browser

You can test the date parsing function with prepared test-cases directly in your browser:

File: parsedate-test-html.html
Open this HTML file to test the date parsing function. The file contains a textarea with the function body code - so you can play with or replace it with yours. It tests different format parsing patterns. You can add/edit/replace test cases directly in the HTML code.

Testing DatepickerTabs Directly

This guide explains how to set up Jest to test your DatepickerTabs component directly, without using a stub implementation.

Setup Steps

  1. First, install the necessary dependencies:

    npm install --save-dev jest jest-environment-jsdom babel-jest @babel/core @babel/preset-env
  2. Create the required configuration files or rewrite them if needed:

    • babel.config.js - For transpiling modern JavaScript
    • jest.setup.js - For setting up the test environment
    • __tests__/direct-import.test.js - The actual tests
  3. Update your package.json with test scripts if not updated:

    "scripts": {
        "build": "gulp build",
        "dev": "gulp",
        "test": "jest",
        "prepare": "npm run build"
    },
    "jest": {
        "testEnvironment": "jsdom",
        "setupFiles": ["./jest.setup.js"],
        "testMatch": [
            "**/__tests__/**/*.test.js"
        ]
    }

File Structure

datepicker-tabs/
├── __tests__/
│   ├── direct-import.test.js
├── babel.config.js
├── jest.setup.js
└── package.json

How It Works

  1. direct-import.test.js: This file reads and loads your original DatepickerTabs code, and runs test cases.
  2. jest.setup.js: This file sets up the browser-like environment needed by DatepickerTabs, including mocking DOM APIs and global objects.

Running Tests

To run the test suite:

npm test

Test Structure

The test suite is organized as follows:

Testing Specific Functionality

Date Parsing

The library includes comprehensive tests for the date parsing functionality, covering various formats and edge cases:

// Example test for date parsing
test('should parse a date in DD/MM/YYYY format', () => {
    const date = datepicker.parseDate('25/05/2025', 'DD/MM/YYYY');
    expect(date instanceof Date).toBe(true);
    expect(date.getDate()).toBe(25);
    expect(date.getMonth()).toBe(4); // May is month 4 (zero-based)
    expect(date.getFullYear()).toBe(2025);
});

We test multiple date formats:

  • DD/MM/YYYY
  • MM/DD/YYYY
  • YYYY-MM-DD
  • DD MMM YYYY
  • DD MMMM YYYY
  • MMM YYYY
  • MMMM YYYY

And various edge cases like:

  • Empty strings
  • Invalid dates
  • Invalid formats
  • Custom separators

Adding New Tests

When adding new functionality, please include corresponding tests. Follow these guidelines:

  1. Create test files in the __tests__ directory
  2. Use descriptive test names that clearly explain what's being tested
  3. Test both success cases and edge/failure cases
  4. Use parametrized tests where appropriate for multiple similar test cases

Example of adding a parametrized test:

const testCases = [
    {
        name: "DD/MM/YYYY - standard date",
        input: "04/07/2025",
        format: "DD/MM/YYYY",
        expected: new Date(2025, 6, 4) // July 4th, 2025
    },
    // Add more test cases...
];

test.each(testCases)('$name', ({ input, format, expected }) => {
    const result = datepicker.parseDate(input, format);

    if (expected === null) {
        expect(result).toBeNull();
    } else {
        expect(result instanceof Date).toBe(true);
        expect(result.getDate()).toBe(expected.getDate());
        expect(result.getMonth()).toBe(expected.getMonth());
        expect(result.getFullYear()).toBe(expected.getFullYear());
    }
});

Adding Single Tests

To extend the test suite, simply add more test cases in direct-import.test.js. For example:

test('should handle special case X', () => {
  const picker = new DatepickerTabs('#date-input');
  // Your test logic
  expect(result).toEqual(expectedValue);
});

Troubleshooting