When searching for hotels, I often specify check in and check out dates with two clicks on the same mini-calendar. The new date picker’s dayFormatter
function let me achieve the same user experience in an APEX app, with some CSS help from my designer colleague Jeff Langlais. I got the basic functionality working; then Jeff updated the stylesheet with his CSS magic to make it sing. Finally, a tip from colleague Stefan Dobre about JavaScript classes unlocked how my Java programming experience could be an asset while learning this new language. It inspired me to refactor my code to make using a date range picker very simple in future APEX apps I build.
Overview of the Strategy
My strategy involved using an inline date picker page item as the “surface” the user interacts with to set and see the date range. The date picker page item works together with two other date fields that capture the actual start and end dates. Depending on the application, it might be desirable for the user to see the start and end dates in an alternative display format. However, in my sample application I decided to set them to be Hidden page items. As shown in the figure below, the dayFormatter
function associated with the date range picker, considers the values of the hidden Check In and Check Out dates to decide how to format the days in the date range between start date and end date. It also decides the appropriate tooltip to show the user based on these values.

CSS Style Classes Involved
The date picker used as the date range picker is tagged with the CSS class date-range-picker
. This allows targeting the CSS style rules so that they only affect date range picker page items, without disturbing the styling of other date pickers used in the application. Next, I identified three different styles required to render the “stripe with rounded ends” look I imagined in my head. As shown below, the CSS class dateRangeStart
represents the start date of the range, the dateRangeEnd
for the end date, and thedateRangeMiddle
class for those days in between. I wrote the dayFormatter
function to return null
for the CSS class
property for any days in the “mini-month” that were before or after the date range. For those days within the range, it returns one of these three CSS class names depending on whether the day being formatted is the beginning, middle, or end of the range. The apex.date
namespace functions parse()
, isSame()
, isBefore()
, isAfter()
, and isBetween()
came in handy for writing the date-related logic in the dayFormatter
function and the date change handler function described later.

After getting the initial dayFormatter
logic working, I realized that some use cases might need a date range that starts and ends on the same day. For example, this would be the case for the dates of a single-day event. To allow for a more visually pleasing single-day date range, I decided a fourth CSS class dateRangeSingleDay
was needed to achieve the appropriate “pill” shape the user would expect a one-day event to have. I adjusted the dayFormatter
function to return this new class name if start date and end date were the same.

Handling Date Range Input & Reset
When the user clicks on a day in the “mini-month” calendar of the date range picker, the Change event will fire for that page item. I wrote the logic of the change handler to work as follows:
- If start date is not set, then set it to the clicked-on date
- Otherwise, if the clicked day is after the start date, then set the end date to the clicked-on date
- If the clicked day is before the current start date, then set start date to the clicked-on date
- Finally, set the date range picker to the value of the start date again, and
- Refresh the date picker item to re-evaluate the
dayFormatter
in the process
When the user clicks on the button to reset the date range picker, the Click event will fire for that button. I wrote the logic of the click handler to:
- Set the value of the start date to
null
- Set the value of the end date to
null
- Set the value of the date picker to
null
- Refresh the date picker item to re-evaluate the
dayFormatter
in the process
Following good practice, I had written the bulk of my JavaScript logic in a shared application file dateRangePicker.js
It defined a dateRangePicker
JavaScript object with three functions:
assignDayFormatter()
called from the Page Load dynamic action eventonChanged()
called from the Change dynamic action event on the date pickerreset()
called from the Click dynamic action event of the reset button
In the page containing the date range picker page item, the hidden start date item, the hidden end date item, and the reset button, I setup dynamic actions to invoke the helper methods like this:

Abstracting Interesting Bits into Metadata
After initially hard-coding the values of the date range picker item, the start date and end date page items, I next tried to add a second date range picker on the same page and rework my code to accept the interesting information as parameters that made the two instances unique. Instead of passing in 10 separate parameters, I decided to pass all the info required as a single parameter in a structured JavaScript object. An example of this parameter object appears below. It captures the names of the page items involved in a single date range picker:
{
picker: {
name: "P2_CHECKIN_CHECKOUT_PICKER",
format: "DD-MON-YYYY",
allowSingleDay: false
},
start: {
name: "P2_CHECKIN",
label: "Check In"
},
end: {
name: "P2_CHECKOUT",
label:"Check Out"
}
}
By passing the appropriate JavaScript object to each of the helper methods, I was able to rework the code to easily support date range pickers on any page in my application and even multiple ones on the same page.
Working in Parallel with a Designer
Since I’m not a CSS expert, I started with the simplest possible dateRangePicker.css
file containing the style classes for the four states the date range picker needed, setting a different font color and italic style for the different date range classes. I used the Chrome browser tools Inspect Element… feature to study what elements and classes would need to be selected by these basic CSS rules. In words, for example, the first rule below selects a <td>
element having the CSS class dateRangeStart
wherever it’s nested inside a containing element with class a-DatePicker-calendar
(the “mini-month”) where that is nested inside a containing <a-date-picker>
element having the class date-range-picker
:
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeStart
{
color: yellow;
font-style: italic;
}
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeMiddle
{
color: darkmagenta;
font-style: italic;
}
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeEnd
{
color: green;
font-style: italic;
}
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeSingleDay
{
color: blue;
font-style: italic;
}
The effect wasn’t exactly what I had predicted, but as shown below I could see after selecting February 13th as the start date and 16th as the end date, that the dates in the date range were showing with the indicated colors and in italic. As you can see below, there was something about the date picker’s default styling of the current date (which, recall, coincides with the start date of the date range) that was overriding my styles. That current date was colored with a blue circle. However, I could see that the font style was italic, so I knew my style rule was correctly selecting that dateRangeStart
day. I also noticed that today’s date was showing in the calendar with a different colored circle.

Rather than trying to become a CSS expert, I decided to pass these requests along to Jeff the designer so that he could incorporate solutions into the final CSS stylesheet he gave me back. In addition to the “stripe with rounded ends” look for the date range, I also asked him to explore hiding the current day indicator. You can explore the sample application’s dateRangePicker.css
static application file to see the CSS magic that Jeff worked to make the date range picker look great. This was a concrete example of how an APEX developer with only the most basic CSS skills could easily collaborate with a highly-skilled CSS web designer to produce a nice-looking result.
Leaning Into JavaScript Classes
As a final step, I asked my colleague Stefan Dobre to review my JavaScript newbie code to suggest any improvements. He recommended I explore further encapsulating the logic of the date range picker into a self-contained DateRangePicker
class. Its constructor could accept the JavaScript object describing the combination of picker, start date, and end date page items, and then internalize the details of:
- Setting the
date-range-picker
CSS class on the picker page item - Assigning the
dayFormatter
function to the picker page item - Adding an event listener to the picker’s Change event to call
onChanged()
By expanding the metadata captured by the constructor to also include the static id of the reset button, the DateRangePicker
class could also internalize adding an event listener to the button’s Click event to call reset()
.
Since I’d programmed for many years in Java in my previous roles at Oracle, the idea of using a class felt second nature. But as a JavaScript neophyte, the idea never crossed my mind. So Stefan’s suggestion unlocked a positive path in my Java brain that will hopefully make future JavaScript development more familiar. You can see the full code for the DateRangePicker
JavaScript class in the sample application’s dateRangePicker.js
static application file, but the skeleton of the implementation looks like this. Its constructor accepts the JavaScript object describing the configuration details of the date range picker page items, sets the date-range-picker
CSS style class on the picker page item, assigns the initial value to the date picker from the start date, assigns a dayFormatter
function to the picker, and wires up the change and click event listeners to run the appropriate code to handle those actions.
window.DateRangePicker = class DateRangePicker {
// Construct the DateRangePicker accepting object that describes
// the picker, start date, end date names, and reset button id
constructor(pConfig) {
this.#config = pConfig;
// Assign the date-range-picker CSS class to the picker
this.#pickerItem().element.addClass("date-range-picker");
// Assign the initial value of the picker from the start date
this.#assignInitialValueFromStartDate();
// Assign the dayFormatter funtion
this.#assignDayFormatter();
// Wire up the change event on the picker to call onChanged()
this.#pickerItem().element.on("change", () => {
this.#onChanged();
});
// Wire up the click event on the reset button to call reset()
document.getElementById(this.#resetId()).addEventListener(
"click", () => {
this.#reset();
})
}
// Private fields ==================================================
#config;
// Private methods =================================================
#assignDayFormatter() {...}
#onChanged() {...}
#reset(){...}
}
With this class in place, you can see how it’s used in page 2 and page 4 of the sample app. Their respective page load JavaScript code contains two simple calls like the following to construct two DateRangePicker
class instances, passing the interesting info into each’s constructor.
// Example from Page 4 in the sample app's Page Load JavaScript
// Setup config for Event Start/End Date Range Picker
// Allows a single day to be both start and end
window.eventStartEndDateRangePicker = new DateRangePicker({
picker: {
name: "P4_EVENT_DATE_RANGE",
format: "DD-MON-YYYY",
allowSingleDay: true
},
start: {
name: "P4_EVENT_STARTS",
label: "Event Start"
},
end: {
name: "P4_EVENT_ENDS",
label:"Event Start"
},
reset: {
id:"Reset_Event_Dates"
}
});
With all the logic encapsulated in the JavaScript class, there is no setup left in the page other than making sure the picker, start date, and end date page items have their Value Protected property set to false and that they all use the same format mask. This resulted in a page you can experiment with in the sample to create or edit the details of an Event. Each Event in the sample app has a start and end date (which can be the same day) as well as a default check in and check out day for event attendees (which must be at least two different days).

Get the Sample App
You can download the APEX 22.2 sample application by clicking here. Thanks again to designer Jeff Langlais for helping me with the CSS styles to deliver the visual idea I had in mind, and to Stefan Dobre for teaching me about JavaScript classes to simplify how to uptake the date range picker functionality in future APEX apps I will build.