javascripthtmlcssdatepickerbootstrap-datepicker

Open two months date picker ( month range picker)


I am using bootstrap date picker. I want to open two month picker in one input. I want to display my input value like this:

How to create a month range picker using Bootstrap Datepicker that allows selecting two distinct months and displays the selected range in the specified format?

What I have done:

  <div class="form-group input-border-label">
       <label for="billing_range">Billing Month Range</label>
       <input type="text" id="billing_range" name="billing_range" required>
  </div>


<script>
 document.addEventListener('DOMContentLoaded', function () {
        $('#billing_range').datepicker({
            format: 'M-yyyy',
            autoclose: true,
            startView: 1,
            minViewMode: 1,
            multidate: true,
            multidateSeparator: ' to ',
            clearBtn: true
        }).on('changeDate', function(e) {
            var currentDates = $(this).datepicker('getDates');
    
            // If only one date is selected, duplicate it (Jan-2025 → Jan-2025 to Jan-2025)
            if (currentDates.length === 1) {
                $(this).datepicker('setDates', [currentDates[0], currentDates[0]]);
            } 
            // If more than 2 dates, keep only the last two
            else if (currentDates.length > 2) {
                $(this).datepicker('setDates', [
                    currentDates[currentDates.length - 2], 
                    currentDates[currentDates.length - 1]
                ]);
            }

        });

    });

</script>

UI image:

UI image


Solution

  • Solution

    $(document).ready(function() {
      let startMonth = null;
      let endMonth = null;
      const $billingRange = $('#billing_range');
      const $monthPopup = $('#monthRangePopup');
    
      function createMonthPicker(target, onSelect, options = {}) {
        $(target).datepicker({
          format: "M-yyyy",
          startView: "months",
          minViewMode: "months",
          autoclose: true,
          ...options
        }).on('changeDate', e => onSelect(e.date));
      }
    
      function updateRangeInput() {
        if (!startMonth || !endMonth) return;
    
        const start = moment(startMonth);
        const end = moment(endMonth);
        const rangeText = `${start.format('MMM-YYYY')} to ${end.format('MMM-YYYY')}`;
        $billingRange.val(rangeText);
        $monthPopup.addClass('d-none');
      }
    
      // Destroy any existing pickers
      $('#startPicker, #endPicker').datepicker('destroy');
    
      // Create Start Picker
      createMonthPicker('#startPicker', function(date) {
        startMonth = date;
        endMonth = null;
        $('#endPicker').datepicker('destroy');
    
        createMonthPicker('#endPicker', function(date) {
          endMonth = date;
          updateRangeInput();
        }, {
          startDate: moment(startMonth).add(1, 'month').startOf('month').toDate()
        });
      });
    
      // Disable endPicker initially by binding to a dummy handler
      createMonthPicker('#endPicker', function() {}, {
        beforeShowMonth: () => false, // diabled all the month
        maxViewMode: 1 // diabled all the year 
      });
    
      // Show popup
      $billingRange.on('click', function() {
        $monthPopup.removeClass('d-none');
      });
    
      // Hide popup on outside click
      $(document).on('click', function(e) {
        if (!$(e.target).closest('#billing_range, #monthRangePopup').length) {
          $monthPopup.addClass('d-none');
        }
      });
    });
    <!-- Required CSS -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css" rel="stylesheet" />
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
    
    <!-- Required JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script>
    
    
    <div class="container">
      <div class="form-group position-relative">
        <div class="input-border-label">
          <label for="billing_range">Maintenance Period</label>
          <input type="text" id="billing_range" name="billing_range" readonly placeholder="Select month range"  class="form-control">
        </div>
    
        <div id="monthRangePopup" class="d-none bg-white border shadow p-3 position-absolute" style="top:100%; z-index: 1050;">
          <div class="d-flex" style="gap:10px;">
            <div id="startPicker"></div>
            <div id="endPicker"></div>
          </div>
        </div>
      </div>
    </div>

    Allowing Same Start and End Month in picker

    To allow users to select the same month for both start and end,

    update this line:

    startDate: moment(startMonth).add(1, 'month').startOf('month').toDate()

    to

    startDate: moment(startMonth).startOf('month').toDate()