Overview
APEX 22.2 introduced a new lighter-weight date picker that is faster, offers better accessibility, and features a flexible day formatter function. Using the Format Date Picker Days plug-in, low-coders can easily format a date picker using a SQL query or an ICS calendar file to style a set of days in the “mini month” calendar used to select a date. In this article we explore the day formatter function, learn what the plug-in can do declaratively, and see how to extend what the plug-in can do while gaining some JavaScript newbie insights in the process.
A Simple dayFormatter
Function
The APEX 22.2 date picker supports an optional day formatter function. You can use it to customize the appearance of any day in its “mini month” calendar. Once you’ve assigned a dayFormatter
function to a date picker, it gets invoked for each day in the mini month when the page item is rendered or refreshed. On each invocation, your function returns an object whose property values determine three aspects of the current day in the mini month:
- Whether the day is enabled or disabled,
- What CSS class (if any) should be used to format the day, and
- What tooltip (if any) should be shown when the user hovers over the day.
Your dayFormatter
function receives a single parameter whose value is the date being formatted. This date parameter value will always be in the standard format YYYY-MM-DD
. Your function must return an object with three properties named disabled
, class
, and tooltip
. The following simple dayFormatter
function ignores the value of the date passed in and just returns the same values for every date. This results in all days being enabled, styled using the CSS class named customDayStyle
, and having the tooltip “Choose a delivery date”:
function (pCurrentDate) {
// Ignore the pCurrentDate and format every day the same
return {
disabled: false, /* Day is not disabled */
class: "customDayStyle", /* Use this CSS class */
tooltip: "Choose a delivery date" /* Use this tooltip */
};
}
In practice, your day formatter function will typically implement conditional behavior based on other factors, using the values returned for the class
and tooltip
parameters to call attention to interesting dates in the mini month. By returning null
for the class
property, it signals that the day should be styled in the normal way, and returning null
for tooltip
indicates that the day will have no tooltip.
Assigning the dayFormatter
During Page Load
Typically, you will assign your day formatter function at page load time. You can either use the Execute when Page Loads block of JavaScript code to accomplish this, or write a JavaScript action step on an Page Load dynamic action event handler. For example, to assign the above dayFormatter
function to a date picker page item named P13_DELIVERY_DATE
, you would write the following block of JavaScript in the Execute when Page Loads script of page number 13. Notice that the last line calls refresh()
on the page item to which you’ve just assigned the day formatter function. This refresh()
call causes the new day formatting function to get used immediately before the user first sees the date picker.
// Assign a dayFormatter function to P13_DELIVERY_DATE date picker
apex.items.P13_DELIVERY_DATE.dayFormatter = function (pCurrentDate) {
// Ignore the pCurrentDate and format every day the same
return {
disabled: false, /* Day is not disabled */
class: "customDayStyle", /* Use this CSS class */
tooltip: "Choose a delivery date" /* Use this tooltip */
};
};
// Refresh the page item to engage the new day formatter
apex.items.P13_DELIVERY_DATE.refresh();
Disabling Weekends in the Mini Month
A common use case is disabling weekends to guide the user to pick a weekday. You can accomplish this by assigning a simple dayFormatter
function that returns true
for its disabled
property for any day that is Saturday or Sunday. The apex.date
namespace contains many useful functions for working with date values in JavaScript. Its parse()
function converts the string format of the day being formatted into a JavaScript Date
object. You can then call the getDay()
method on the Date object to get the day of the week (0=Sunday, 1=Monday, …, 6=Saturday). So, the following slightly modified dayFormatter
only allows the user to pick a weekday for a delivery date, uses no CSS class, and returns no tooltip for weekend days that are disabled:
// Assign a dayFormatter function to P13_DELIVERY_DATE date picker
apex.items.P13_DELIVERY_DATE.dayFormatter = function (pCurrentDate) {
// Parse the current day's date using ISO8860 format mask
const curDate = apex.date.parse(pCurrentDate,"YYYY-MM-DD");
const dayOfWeek = curDate.getDay();
const isWeekend = (dayOfWeek == 6 /*Sat*/ || dayOfWeek == 0 /*Sun*/);
return {
disabled: isWeekend,
class: null, /* no day formatting class */
tooltip: isWeekend ? null /* no tooltip for weekend, else... */
: "Choose a delivery date"
};
};
// Refresh the page item to engage the new day formatter
apex.items.P13_DELIVERY_DATE.refresh();
This produces the following effect:

P13_DELIVERY_DATE
date picker showing disabled weekends and a custom tooltipGetting the Format Date Picker Days Plug-in
The APEX team’s GitHub site has a Format Date Picker Days plug-in you can use to handle some day formatting use cases declaratively using either an ICS calendar file or a SQL query. To download the plug-in, visit https://oracle.github.io/apex/, scroll down to the Plug-ins section of the page shown below, and right-click on the Download Plug-In link to choose the “Save Link As…” (or similar) option in your browser. This will save a plug-in file named dynamic_action_plugin_format_datepicker_days.sql
to your computer. You can import this file as a plug-in into any APEX 22.2 application or later.

Formatting Dates Using an ICS File
The 22.2.2 version of the Sample Calendar app in the gallery has a Day Formatting (Plug-in) page 540 that contains two examples of date pickers using the Format Date Picker Days plug-in to show American holidays using the Universal Theme color class u-hot-text
. One date picker is the page item P540_US_HOLIDAYS_PLUGIN
that references a public Google Calendar URL to the ICS file for holidays in the USA. It is configured using Page Load dynamic action named Load US Holidays into Date Picker that uses an action step of type Format Date Picker Days [Plug-In] as shown below.

The result is that american holidays in the calendar show with the universal theme’s “Hot Text” CSS class like this:

u-hot-text
CSS classThe same page uses a Row Initialization [Interactive Grid] dynamic action to format the START_DATE
date picker column in an Interactive Grid region on the page using the same ICS calendar file.
Formatting Dates Using a SQL Query
The Announcements sample you can download at the end of this article is a simple app that lets the user enter time-sensitive announcements. Each announcement has a display from date, a display to date, and a purge date. For the sake of argument, let’s say that announcements are only purged on the last day of the month and that we want to let the user pick a purge date only in the next three months.
By configuring the Page Load dynamic action to use an action step of Format Date Picker Days [Plug-In], we can choose the SQL Query option and use a query like the one below to return the next three last days of the month. The query uses two union all
operators and the SQL last_day()
and add_months()
functions to return a total of three rows. The first has the last day of the current month. The second row has the last day of the next month. And the third row has the last day of two months from now. Notice that each of the three select
statements returns the same date value for the start_date
and end_date
column since they are single-day periods. However, the plug-in supports returning a range of consecutive days as a single (start_date
, end_date
) pair of values in a row. All the days in that date range will be styled as indicated by the other column values in that row.
select /* last day of this month */
trunc(last_day(sysdate)) as start_date,
trunc(last_day(sysdate)) as end_date,
'bold-and-red' as css_class,
'Purge Day' as tooltip,
0 as is_disabled
from dual
union all
select /* last day of next month */
trunc(last_day(add_months(sysdate,1))) as start_date,
trunc(last_day(add_months(sysdate,1))) as end_date,
'bold-and-red' as css_class,
'Purge Day' as tooltip,
0 as is_disabled
from dual
union all
select /* last day of month after that */
trunc(last_day(add_months(sysdate,2))) as start_date,
trunc(last_day(add_months(sysdate,2))) as end_date,
'bold-and-red' as css_class,
'Purge Day' as tooltip,
0 as is_disabled
from dual
Next you ensure that your plug-in usage correctly configures the names of the query result columns that provide the appropriate values that drive the formatting as shown below, making sure to enter any page item names into the Item to submit field if the query references them as bind variables:

The bold-and-red
CSS class is defined in the Inline CSS section of the page. I originally had defined it like this:
.bold-and-red {
font-weight: 900 !important;
color: var(--ut-palette-danger) !important;
}
However, when that was not working for me, my colleague Ronny gave me the tip that some important changes to improve the accessibility of the date picker required that I write the style rule like this instead:
.bold-and-red {
}
.bold-and-red > span {
font-weight: 900 !important;
color: var(--ut-palette-danger) !important;
}
This produces the Purge Date date picker that shows the last day of the next three months in bold red text like this:

Using SQL to Specify Only Available Days
Using the three rows returned by my SQL query above, the Format Date Picker Days plug-in formatted those three days in a special way. But, what if I wanted those three days to be the only three days the user can pick? Using the plug-in on its own, this requires writing a query that retrieves a row for each start and end date range that I wanted to declaratively disable, using 31-DEC-9999
to represent the “End of Time”. Maybe for some use cases that would be easy to do, but as a general strategy it seemed complicated to determine. So, I experimented with the idea of combining the declarative plugin’s behavior with the ability to write a custom dayFormatter
function to see if I could accomplish my desired goal in a more general way.
What I discovered is that the plug-in implements its declaratively-configured functionality by assigning an appropriate dayFormatter
function to the date picker page item. It’s a day formatter function the low-code developer did not have to write herself, but a day formatter function nonetheless. My strategy was to first let the plugin assign its day formatter function, then to incorporate that day formatter function into my own day formatter function implementation. This way, I could “intercept” the day by day formatting and override the disabled
property to disable all days by default unless the day was explicitly enabled by the plug-in’s day formatter function.
The day formatter function I devised is configured in a Page Load dynamic action event handler step of type Execute JavaScript that immediately follows the action step using the Format Date Picker Days [Plug-in] type to perform the SQL-based declarative configuration. I’ve used the 22.2 feature of more descriptive action step names to make the intent of the dynamic action more easy to read:

The code of the “…and Enable ONLY Those Three Days” action steps appears below. It effectively replaces the day formatter function configured by the previous dynamic action step by the plugin, with a new day formatter function that first delegates to the plug-in-configured function, then overrides the return value of the disabled
property to return true
for all other days in the mini month:
// Access the dayFormatter the Plug-in just assigned before this
const pluginFormatter = apex.items.P3_PURGE_DATE.dayFormatter;
// Replace the date picker's dayFormatter with my own
apex.items.P3_PURGE_DATE.dayFormatter = function (pDateISOString) {
// That first invokes original pluginFormatter to get its result object
const plugInFormatterResult = pluginFormatter(pDateISOString);
// Then returns a result that defaults disabled to true
return {
// disable by default if not in plug-in formatter's result object
disabled: 'disabled' in plugInFormatterResult
? plugInFormatterResult.disabled : true,
// return class if in plug-in formatter's result object
class: 'class' in plugInFormatterResult
? plugInFormatterResult.class : null,
// return tooltip if in the plug-in formatter's result object
tooltip: 'tooltip' in plugInFormatterResult
? plugInFormatterResult.tooltip : null
};
};
apex.items.P3_PURGE_DATE.refresh();
The result, is a mini month for the Purge Date field of an announcement that only allows the last day of the current and two successive months to be selected. And these three days are formatted with an extra bold, “urgent” (red) color to highlight the destructive nature of the announcement purge operation.

A Lesson Learned on Async Nature of JavaScript
My earlier attempts to get this “delegating day formatter” idea to work were not functioning as expected. My colleagues Stefan Dobre and Ronny Weiss helped me understand that this was due to the asynchronous nature of the JavaScript language. When two dynamic action steps are listed in sequence, if an earlier step performs an AJAX call to the APEX server, the second step in the sequence might execute before the first one has completed. The Format Date Picker Days plug-in retrieves the results of the SQL statement by performing a round-trip to the APEX engine on the server. However fast this operation may be, it is still a network exchange that takes some time. I learned from my colleagues that all I needed to do was ensure the “Wait for Result” property of the plug-in was switched to the on position as shown in the figure below. This setting guaranteed my delegating day formatter code would only run after the plug-in had retrieved its data and successfully setup its day formatter function first. After checking that setting, everything starting working correctly.

Getting the Sample App
To check out the APEX 22.2 Announcements sample app that has the Purge Date date picker page item described above on the modal drawer page (3) used to create or edit an announcement, download the app from here. As mentioned above, also explore page 540 in the 22.2.2 version of the Sample Calendar app. Thanks again to my colleagues Stefan and Ronny for the precious advice they offered while working on this example.