[SalesForce] Using LWC Component blueprint for custom date picker

Salesforce's date picker only allows you to select 1 date, but I want a date range picker. I found that the SLDS component blueprints seem to have static code for one here, but was wondering if Salesforce provides a date range picker as a web component, the way a single date picker is provided here.

Best Answer

The Datepicker range selector shown in the Lightning Design System Library is just the CSS part - the javascript logic for those blueprints are not fully implemented.

Currently the out of box components like lightning-input type=date does not support a range functionality as shown in the lightning design system documentation (although it might be in salesforce roadmap for future releases).

This request has been an idea for quite some time.

Idea-exchange link: https://success.salesforce.com/ideaView?id=08730000000lCO6AAM

For now - there are 2 approaches

  1. Build a custom lwc for input type=date field - Probably use a custom third party date picker which supports range functionality and uses the CSS from the SLDS library. This would require some effort.
  2. Or if you still want to make use of the out of box functionality (lightning-input type=date) - You could achieve a partial functionality for the range selection using the lightning-input type=date.

    • Use @track or @api to pass the start date & end date, and you should be able to calculate the Number of Selected Dates between the start & end Dates.
    • you can do some validations on the on value change of start date and end date to ensure that the selected end date is always greater than the start date and other stuff.

Here is a basic example of the second approach, you could implement or enhance something as follows.

rangeSelector.html

<template>
    <lightning-card  title="Range Selector">
        <div class="slds-grid slds-gutters">
            <div class="slds-col slds-m-left_large">
                <lightning-input type="date" name="startdate" class="startdate" label="Start Date" value={start_date} onchange={handleDateChange} required ></lightning-input>
            </div>
            <div class="slds-col slds-m-right_large">
                <lightning-input type="date" name="enddate" class="enddate" label="End Date"  value={end_date} onchange={handleDateChange} required></lightning-input>
            </div>
        </div>
        <div class="slds-grid slds-gutters">
            <div class="slds-col slds-m-left_large">
                <div class="slds-text-color_error slds-p-top_medium">No Of Days Selected : {range}</div>
            </div>
        </div>
    </lightning-card>
</template>

rangeSelector.js

import { LightningElement, track, api } from 'lwc';
export default class RangeSelector extends LightningElement {
    today = new Date();
    @track start_date;
    @track end_date;
    @track range;

    connectedCallback() {
        this.start_date = (this.start_date) ? this.start_date : this.today.toJSON().slice(0,10);
        this.end_date = (this.end_date) ? this.end_date : this.addDays(this.today,1).toJSON().slice(0,10);
        this.range = this.diff(this.start_date,this.end_date);
    }

    addDays = (sd,days) => {
        const d = new Date(Number(sd));
        d.setDate(sd.getDate() + days);
        return d;
    }

    diff = (sdate,edate) => {
        let diffTime = Math.abs(new Date(edate).getTime() - new Date(sdate).getTime());
        return Math.ceil(diffTime / (1000 * 60 * 60 * 24));
    }

    valid_date = (sdate,edate) => {
        return new Date(edate) >= new Date(sdate);
    }

    handleDateChange = (evt) => {
        let field_name = evt.target.name;

        if(field_name === 'startdate')
            this.start_date = evt.target.value; 
        if(field_name === 'enddate')
            this.end_date = evt.target.value; 

        if(this.valid_date(this.start_date,this.end_date) === true){
            this.range = this.diff(this.start_date,this.end_date);
        }else{
            let inputfield = this.template.querySelector("."+field_name);
            inputfield.setCustomValidity('End date must be greater than the Start date'); 
            inputfield.reportValidity();
        }
    }
}

One caveat that I observe with the second approach is that -

  • Since this is a salesforce authored component, you would be able to control the datepicker's UI & CSS - the range selection cannot be shown in the date picker visually.

Output

Num of Days

Custom Validity