The LowDown
My sixth attempt writing a datePicker (calendar) that is accessible using the keyboard and uses no pop-up windows.
The more impatient amongst you may want to see the various demos or head directly over to github to ponder over the source before reading any further.
It’s also worthwhile noting that:
- All examples within the article use a European d/m/y date format and not the American m/d/y format
- A basic knowledge of Javascript, HTML and CSS is assumed
At a glance…
- Keyboard shortcuts adhere to The DHTML Style Guide Working Group (DSGWG) recommendations
- Accessibility enhancements including support for ARIA Roles and States
- The script can parse and format dates using a subset of the PHP date conversion specifiers
- Both upper and lower date limits can be set
- Bespoke days of the week can be disabled
- Bespoke dates can be disabled/enabled and wildcards used to stipulate the dates in question
- Bespoke days of the week can be highlighted
- Works with any combination of text inputs or select lists
- DOM friendly – the calendar is only added to the DOM when actually required
- Includes a “smart” localisation option
- Can display an optional status bar and week numbers
- Can be dragged within the viewport by the user
- Global configuration parameters can be specified using JSON within the script tag itself
- The “button” used for popup datePickers can now be styled for default, hover, focus, active and disabled states, be arbitrarily positioned within the DOM and removed from the document tabindex if so desired
- Inline datePickers are now available (i.e. no button activation is required), are automatically added to the documents tabindex and can be arbitrarily positioned within the DOM
- A bespoke final opacity can be defined and the fade in/out animation effect disabled
- The entire grid can now be filled with dates
- The “Today” button can be removed from the U.I.
- No pesky images to upload and track on your server – they have all been (Base64) encoded directly into the CSS file
Creating datePickers
Datepickers are created by calling the datePickerController.createDatePicker method. An example of a basic Javascript creation call is shown below:
// Attach a datepicker to the form element with an id of "inp1"
// Use the date format "%d/%m/%Y" i.e. 03/12/2009
datePickerController.createDatePicker({
formElements:{"inp1":"%d/%m/%Y"}
});
Note: All associated form elements have to be available within the DOM before calling the createDatePicker method. This means that the createDatePicker method should only ever be called from:
- A window.onload event handler (old school)
- A bespoke onDomReady event handler (new school)
- An inline script block positioned after the form elements within the HTML (lazy school – as used within the demo)
Associating form elements with a datePicker
Each datePicker has to be associated with at least one form element (a text input or selectList) and each form element has to have an associated date format.
For example, the following code will associate a datePicker with the three distinct form elements whose id’s are “inp1”, “inp2” and “inp3” respectively:
datePickerController.createDatePicker({
formElements:{
// "inp1" represents the day part
"inp1":"%d",
// "inp2" represents the month part
"inp2":"%m",
// "inp3" represents the year part
"inp3":"%Y"
}
});
Note: Each datePicker has to have a day, month and year part stipulated within the combined date formats in order for the script to be able to parse a valid date from the combined form element values.
The order of the form elements listed within the formElements parameter
The first form element stipulated within the formElements parameter is the element that receives focus after a date has been successfully selected using the datePicker; for example, the following initialisation code would set the focus on the “inp1” form element as it was the first element listed:
datePickerController.createDatePicker({
formElements:{
/* "inp1" will be given focus whenever a date is selected
using the datePicker */
"inp1" : "%d",
"inp2" : "%m",
"inp3" : "%Y"
}
});
Additionally, the first form element listed is the id that needs to be used when calling certain methods of the datePickerController Object as is shown below:
/* "inp1" is the id to use when calling certain methods of the "datePickerController" Object; for example, the "destroyDatePicker" method */
datePickerController.destroyDatePicker("inp1");
Popup datePickers
By default, the script creates “popup” datePickers i.e. an activation button is positioned beside the associated form element and the datePicker only appears when the button has been activated (by using either the mouse or keyboard).
The activation button (actually an HTML link styled to look like a button – which keeps it in the document tabindex) is, by default, positioned directly after the associated form element within the DOM.
The bespoke positioning of the popup datePickers’ activation button
Should you wish to position a the activation button within a bespoke DOM node, just add the parameter “positioned” to the initialisation Object and give this parameter the ID of the DOM node that you wish to position the button within.
For example, the following code will instruct the script to create the button within the DOM node whose id is set to “someNodeId”:
var opts = {
formElements:{"inp1" : "%d/%m/%Y"},
/* Tell the script to position the button within
a the DOM node whose id is "someNodeId" */
positioned : "someNodeId"
};
datePickerController.createDatePicker(opts);
Removing the button from the document tabindex
This can be done by using the “buttontabindex” property within the JSON passed to the script – this is explained in more detail within the section Setting Global configuration parameters.
Inline (non-popup) datePickers
If you wish to have the datePicker always displayed on screen i.e. with no activation button; just add the parameter “staticPos” to the initialisation Object and set its value to “true”. By default, the script adds inline datePickers to the DOM as the next sibling of the first associated form element.
The bespoke positioning of inline datePickers
Should you wish to position inline datePickers within a bespoke DOM node, just add the parameter “positioned” to the initialisation Object and give this parameter the ID of the DOM node that you wish to position the datePicker within.
For example, the following code will instruct the script to create the datePickler within the DOM node whose id is set to “someNodeId”:
var opts = {
formElements:{"inp1" : "%d/%m/%Y"},
/* Tell the script we want a static/inline datePicker */
staticPos:true,
/* Tell it also to position the datePicker within a
specific DOM node */
positioned:"someNodeId"
};
datePickerController.createDatePicker(opts);
Date formats
The following list of conversion specifiers are valid for use within the date format:
| Specifier | Description |
|---|---|
| %d | Day of the month, 2 digits with leading zeros (01 – 31) |
| %j | Day of the month without leading zeros (1 – 31) |
| %D | An abbreviated textual representation of a day (Mon – Sun) |
| %l | A full textual representation of the day of the week (Monday – Sunday) |
| %N | ISO-8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday) |
| %w | Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday) |
| %S | English ordinal suffix for the day of the month: st, nd, rd or th |
| %W | ISO-8601 week number of year, weeks starting on Monday: 1 – 53 |
| %M | A short textual representation of a month, three letters |
| %F | A full textual representation of a month, such as January or March |
| %m | Numeric representation of a month, with leading zeros |
| %n | Numeric representation of a month, without leading zeros |
| %t | Number of days in the given month: 28 through 31 |
| %Y | A full numeric representation of a year, 4 digits |
| %y | A two digit representation of a year |
Date parsing
The script now has a much more forgiving approach to parsing dates and no longer forces you to rigidly enter dates in the date format associated with the form element.
The script will first check to see the form element value matches the associated date format; if not, it attempts to match the form element value against various combinations of the date format parts.
For example, it is possible to stipulate “%m” as the month format part (i.e a zero filled two character representation of the month) but the script will accept a single character, an English short-hand or long-hand month name and if a language file has been loaded, a short-hand or long-hand month name in that language. For example, if the French language file has been loaded, the script will accept the values “01”, “1”, “january”, “jan” or “janvier”.
The associated form element value is automatically updated to reflect the desired date format i.e. the date format expected on the server.
Displaying a status bar
To show a status bar, just add the parameter “statusFormat” to the initialisation object and set its value to the desired date format; for example
opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Tell the script to add a status bar and set its date format
// The format below will create dates like:
// "Monday, 2 September 2009"
statusFormat:"%l, %d %F %Y"
};
datePickerController.createDatePicker(opts);
Showing Bespoke messages within the status bar
The script enables you to show short, bespoke text messages within the status bar.
…for all datePicker instances
Setting bespoke titles to be shared across all datePickers can be achieved by calling the datePickerController.setGlobalOptions method or using JSON within the script tag – this is explained in more detail within the section Setting Global configuration parameters.
…for a single datePicker instance
To set messages only for a specific datePicker instance, just add the parameter “bespokeTitles” to the initialisation object and set its value to itself be an Object of key/value pairs where the keys represent a YYYYMMDD date and the values, the message to show for the date in question. For example:
opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Tell the script to add a status bar
statusFormat:"%l, %d %F %Y",
// Add bespoke messages for certain dates
bespokeTitles:{
// Show a title for the 25th of December for all years
"****1225":"Christmas Day",
// Show a title for the 13th of March for all years
"****0313":"My Birthday"
}
};
datePickerController.createDatePicker(opts);
This can also be achieved by calling the “setBespokeTitles” or “addBespokeTitles” methods of the datePickerController Object.
Highlighting days of the week
By default, Saturday and Sunday are highlighted in another colour (the default skin uses a burgundy red). Should you wish other days of the week to be highlighted instead, just add the parameter “highlightDays” to the initialisation object and set its value to be a seven item Array of “0” or “1” values where each index represents a day of the week (index 0 represents Monday through index 6, which represents Sunday).
For example, the following code will set Monday and Tuesday to be highlighted instead of the default Saturday and Sunday:
var opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Highlight Monday (index 0) and Tuesday (index 1)
highlightDays:[1,1,0,0,0,0,0]
};
datePickerController.createDatePicker(opts);
Localisation
The script attempts to detect the language of the current HTML page (by attempting to grab the value of the HTML nodes lang attribute). If a language code is successfully detected by the script, it then attempts to download the corresponding language file from the server.
Should the detected language have a region code set (i.e. en-US), the script will also attempt to download the language file associated with this region code.
If the language file does not exist on the server or the script is unable to detect a language, the datePicker display defaults to English.
Filepaths and language files
In order for the script to successfully detect the language and download the appropriate file, the language files should be placed within a directory named “lang”, itself resident within the same directory as the datepicker.js file.
Currently available languages
The following languages are currently available:
- American English
- Arabic (Thanks to hosam alaa eldien)
- Brazilian Portuguese (thanks to “g0dkar”)
- Catalan (thanks to Thomas Sjödin Dahl)
- Czech (thanks to Stano Matousek)
- Danish (thanks to Brian Jensen)
- Dutch (thanks to Alfred Vorsselman)
- Esperanto (thanks to Greg Naçu)
- Estonian (thanks to Kaius Karon)
- French
- Finnish (thanks to Keijo Mukku)
- German (thanks to “too many people to list”)
- Hebrew (thanks to Neil Osman)
- Hungarian (thanks to Hetesi Tams)
- Indonesian (thanks to Krishna Hendrakusuma)
- Italian (thanks to Valerio Pilo)
- Korean (thanks to Taehyun Kim)
- Latvian (thanks to Māris Kiseļovs)
- Norwegian (thanks to Geir Rune Brandt)
- Portuguese (thanks to Paulo Monteiro)
- Russian (thanks to Кирилл Асташов)
- Spanish (thanks to Augusto)
- Swedish (thanks to Henrik Marik)
- Turkish (thanks to Ogan Keskiner)
Many thanks to the above contributers for their time and effort in creating the localisations.
Creating a bespoke language file
If you don’t see your language in the list, you can easily create one by using the language file creator script. I would, of course, appreciate a copy of the new file to add to the distribution – thanks!
Stipulating a language to use
You can disable the detect locale functionality and stipulate the required language by either using JSON within the script tag – this is explained in more detail within the section Setting Global configuration parameters – or by adding the desired language.js file before the datepicker.js file as is shown below:
<!-- Add the French "fr.js" file -->
<script type="text/javascript" src="/the/path/to/fr.js"></script>
<!-- Now add the datepicker.js file -->
<script type="text/javascript" src="/the/path/to/datepicker.js"></script>
Stipulating a language directly like this is recommended as it incurs only one extra HTTP request (that has a good probability of success) whereas the automatic detect language functionality requires up to two HTTP requests (with a lower probability of success).
The locale used when formatting dates that include non-numeric date parts
Should no language be explicitly defined for use as described above (i.e. the auto-detect functionality has kicked in and downloaded a language file from the server), the date displayed within the status bar and TD nodes will display using the downloaded locale but all dates formatted for updating the associated input value will display in English.
This is to make life easier on the server, as you know for certain that English (and not Spanish or French for example) dates are being returned for processing e.g. the English version “Friday, 13 March 1970” will be returned and not the French “Vendredi, 13 Mars 1970”.
Should a language be explicitly defined, the date returned to the server will always use this language.
The “first day of the week”
The first day of the week is stipulated within the downloaded language file (as logically, it’s a locale-specific setting). Should the language file not contain this setting, the first day of the week defaults to Monday.
Additionally, users can click on any of the day headers to dynamically set it as the first day of the week (or alternately, press the numbers 2-7 on the regular keyboard or numpad whenever the datePicker is keyboard aware).
Limiting date selection i.e. setting date ranges
The datePicker enables you to define both a lower and upper limit for date selection.
To add a lower or upper limit, just add the parameters “rangeHigh” and/or “rangeLow” to the initialisation object and set their values to be a YYYYMMDD date format String; for example, the following code will limit date selection outside of the range 13/03/1970 to 20/12/1999:
var opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Set a range low of 13/03/1970
rangeLow:"19700313",
// Set a range high of 20/12/2009
rangeHigh:"20091220"
};
datePickerController.createDatePicker(opts);
Selectlists and automatic date ranges
As a selectlist can only ever stipulate a finite range, the datePicker will automatically create a higher and lower date limit using the selectlist data if the selectlist is used to represent the year part of the date format i.e. if the year select list starts at 1960 and ends at 1990, the associated datePicker will automatically disallow the selection of dates outside of this range.
Setting the date range dynamically
The upper and lower date ranges can also be set programmatically by calling the following two methods:
// Set the lower limit to be 01/12/2008
datePickerController.setRangeLow("myElementID","20081201");
// Set the upper limit to be 01/12/2009
datePickerController.setRangeHigh("myElementID","20091201");
It is possible to pass either a “YYYYMMDD” formatted date String or a JS Date Object as the second argument to both methods.
Disabling day selection
Should you wish to disable certain days of the week, just add the parameter “disabledDays” to the initialisation object and set its value to be a seven item Array where each index represents a day of the week (index 0 represents Monday through index 6, which represents Sunday).
For example, the following code will disable both Saturday and Sunday:
var opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Disable Saturday (index 5) and Sunday (index 6)
disabledDays:[0,0,0,0,0,1,1]
};
datePickerController.createDatePicker(opts);
Disabling date selection
Dates can be programmatically disabled by calling the setDisabledDates or addDisabledDates methods of the datePickerController Object.
Both methods accept an Object that represents the dates or date ranges to disable.
The setDisabledDates method will delete the current list of disabled dates before adding the new ones while the addDisabledDates method will add the dates to the list of dates already present.
Wildcards can be used when stipulating the dates to disable/enable by substituting the day, month or year parts with the wildcard character “*”.
var opts = {
formElements:{"inp1":"%d/%m/%Y"}
},
disabledDates = {
// Single Date: Disable 25/12/2009
"20091225":1,
// Single Date: Disable the 31th of December for all years
"****1231":1,
// Date Range: Disable from the 1st of January 2011 to the
// 20th of January 2011
"20110101":"20110120"
};
datePickerController.createDatePicker(opts);
datePickerController.setDisabledDates("inp1", disabledDates);
Enabling date selection
Should you wish to enable dates that have been previously disabled then use the setEnabledDates or addEnabledDates methods of the datePickerController Object.
Both methods accept an Object that represents the dates or date ranges to disable.
The setEnabledDates method will delete the current list of enabled dates before adding the new ones while the addEnabledDates method will add the dates to the list of dates already present.
Disabling the fade in/out animation effect
To disable the fade-in/fade-out effect, just add the parameter “noFadeEffect” to the initialisation object and set its value to “true”; for example:
var opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Don't fade in/out the datePicker
noFadeEffect:true,
};
datePickerController.createDatePicker(opts);
Setting a bespoke opacity
To set a bespoke final opacity for a datePicker, just add the parameter “finalOpacity” to the initialisation Object and set its value to to be an Integer value between 20 and 100; for example:
var opts = {
formElements:{"dp1":"%d/%m/%Y"},
// Set a final opacity of 80%
finalOpacity:80
};
datePickerController.createDatePicker(opts);
Showing week numbers
To display week numbers, just add the parameter “showWeeks” to the initialisation object and set its value to true.
Removing the “Today” button from the U.I.
To remove the button, just add the parameter “noTodayButton” to the initialisation object and set its value to true.
Setting the default cursor date
By default, the cursor date is set to today’s date but there may be times when you wish the cursor to start at a date of your choice (when stipulating a range of valid dates, you may wish for the cursor to start in the middle of the range for example).
To set the cursor date to a date of your choice, just add the parameter “cursorDate” to the initialisation object and set its value to be either a YYYYMMDD format date String or JS Date Object.
Hiding the associated form elements
To hide the associated form elements, just add the parameter “hideInput” to the initialisation object and set its value to “true”. The form elements will then be given the class “fd-hidden-input” which, if using the default stylesheet, sets the elements display property to none (which still sends a value to the server whenever the form submit is fired).
Disabling the drag effect
To disable the drag effect for an individual popup datePicker, just add the parameter “noDrag” to the initialisation Object and set its value to “true”.
Disabling the drag effect for all datePickers
Disabling the drag effect for all datePickers can be achieved by calling the datePickerController.setGlobalOptions method or using JSON within the script tag – this is explained in more detail within the section Setting Global configuration parameters.
Filling the entire grid with dates
Should you wish to fill the entire grid with dates, just add the parameter “fillGrid” to the initialisation object and set its value to “true”.
Stopping the selection of “out-of-month” dates
By default, all dates on the calendar grid can be selected. To constrain the selection of dates to the current in-view month only, just add the parameter “constrainSelection” to the initialisation object and set its value to “true”.
Of course, this parameter is only taken into consideration when the “fillGrid” parameter has been set to true.
Styling the datePicker
The datePicker currently ships with a rather basic CSS skin that, for simplicities sake (yours, not mine), attempts to Base64 encode the required images directly into the CSS file – even in Internet Explorer.
The file is well commented so altering the colours etc to suit your installation should be a relatively easy task for those of you knowledgeable in the dark arts of CSS. Remember to resave the file with DOS line-endings in order to keep Internet Explorer happy as it appears to require DOS line-endings in MHTML blocks.
A little CSS3 animation flourish has been added in the form of a pulse effect on the activation button and current cursor cell (when keyboard enabled). This, of course, won’t work in Internet Explorer (< 10) but the CSS file should degrade gracefully in older browsers.
Additionally, the icon used to activate the datepicker changes slightly if the associated form element(s) represent a valid date (as mentioned, a very slight change but it’s the little things in life…).
A version of the CSS file that does not use Base64 encoded images (and the images themselves) are also available in the download bundle.
Styling individual dates
To enable you to target and style individual dates, each TD node rendered within the interface is given two extra classNames of the format yyyymm-YYYYMM and mmdd-MMDD, where MM is replaced by the two figure month value and YYYY replaced by the four figure year value e.g. the TD node for the date 21/03/2007 will be given the classNames “yyyymm-200703” and “mmdd-0321”.
Setting Global configuration parameters
The script accepts the passing of Global configuration parameters by using a JSON Object within the script tag – an example of this is shown below:
<!-- Notice how the JSON Object is passed within the script tag -->
<script type="text/javascript" src="/the/path/to/datepicker.js">
{
"nodrag":1,
"lang":"en",
"buttontabindex":true,
"cellformat":["Y-ds-m-ds-d"],
"titleformat":["Y-ds-m-ds-d"]
}
</script>
It’s worth noting that JSON notation doesn’t care about whitespace so the above code block could have been written in one line (with no line breaks).
Should a JSON parser exist, it is used to parse the JSON passed to the script.
Additionally, you can programmatically pass the JSON Object by calling the datePickerController.setGlobalOptions method as is shown below:
<!-- Load the datePicker script -->
<script type="text/javascript" src="/the/path/to/datepicker.js"></script>
<!-- Now create our JSON Object and pass it to the "setGlobalOptions" method -->
<script type="text/javascript">
// Create the JSON Object
var myJSON = {
// disable the drag & drop for all datePickers
"nodrag":1
};
// Pass it to the script immediately...
datePickerController.setGlobalOptions(myJSON);
</script>
It is also worth noting that only the variables you wish to set need to be defined within the JSON Object; for example, should you only wish to disable the drag effect for all datePickers, you would use a JSON Object of the form:
{
"nodrag":1
}
The following parameters can be passed to the script using JSON:
- “nodrag”
- Accepts a Boolean value that, when set to ture, disables the drag effect for all datePickers.
- “lang”
- Accepts a valid rfc4646 language code e.g. “de” for German and, if required, an optional region subtag e.g. “de-CH”, and attempts to retrieve the corresponding language file from the server. This variable is only taken into consideration when passing the JSON between the script tags and has no effect if passed to the
setGlobalOptionsmethod. - “cellformat”
- Accepts a date format String that is used to create the full date for each TD cell whenever the the associated datePicker has keyboard control. This parameter defaults to the value “%d %F %Y” i.e. “13 March 1970”. Only the date format parts “%d” or “%j” are visibly displayed (which means that they have to be present within the date format), the rest is hidden from view but made available to screen-readers.
- “titleformat”
- Accepts a date format String that is used to create the title attribute for each TD cell. This parameter defaults to a screen-reader friendly value of “%F %d, %Y” i.e. “March 13, 1970”
- “statusformat”
- Accepts a String value that is used as the default statusbar date format for all datePickers
- “cellformat”
- Accepts a String value that is used to define the default date format used within the datePicker interface. Only the day date parts (%d and %j) will be shown visually – all other date parts are hidden from view but made accessible to screen-readers
- “buttontabindex”
- Accepts a Boolean value that adds or removes all popup datePicker activation buttons from the document tabindex (Note: Removing the buttons from the document tabindex means that the associated datePicker cannot be controlled using the keyboard).
- “mousewheel”
- Accepts a Boolean value that enables or disables the mouseWheel activity for all popup datePickers.
- “describedby”
- Accepts a String value that represents the id of the DOM node to use for the ARIA described-by property.
- “finalopacity”
- Accepts an Integer value between 20 and 100 and sets the finalOpacity for all pop-up datePickers.
- “bespoketitles”
- Accepts an Object whose keys represent a YYYYMMDD date and whose values represent the Message to display within the statusbar for the date in question. Wildcards are accepted for both the Year and Month parts of a key.
- “derivelocale”
- Accepts a Boolean value that enables or disables the smart localisation feature. Only taken into account when the JSON is passed within the script tag.
The active “cursor”
An active cursor is necessary as the datePicker is keyboard accessible and keyboard users require a visual clue as to which date is currently active i.e. which date will be selected when the carriage return key is pressed.
The default sylesheet shows the selected date with a black border and black text and the current cursor position in blue.
Accessibility
The datePicker now includes features designed with assitive technologies in mind.
The table structure
The HTML table representing the datePicker has been marked up with a THEAD, TBODY and, if a status bar is used, a TFOOT.
The TH nodes representing the day names have their scope attribute set to “col” and the nodes representing the week numbers, if used,
have their scope attribute set to “row”.
The use of the TITLE attribute
Each focusable TD node has been given a title attribute that uses a default format of “%F %d, %Y” to describe the cells representative full date, for example, “March 13, 1970”.
As some screen reader users disactivate the reading of title attributes, I also add the full date to each TD node but display only the day part of the date. All other date parts are hidden within span nodes that are positioned off-screen.
This means that screen reader users will still have a full date read aloud whenever the active “cursor” is given focus by the script.
By default, the TD cell date format is of the form “%d %F %Y” i.e “13 March 1970” but both this and the title format can be changed to suit your needs by passing JSON within the script tag – this is explained in more detail within the section Setting Global configuration parameters.
Keyboard accessibility
All keyboard shortcuts – with the exception of the space bar – now adhere to The DHTML Style Guide Working Group (DSGWG) recommendations.
Keeping the keyboard or mouse button depressed activates a timed increment i.e. there’s no need to repeatedly press the mouse button or arrow keys in order to change the month or year value within the interface.
Pressing Enter selects the currently highlighted date, pressing Esc closes the datePicker without selecting a date and Space highlights today’s date. Additionally, pressing 2 to 7 (using the numpad or regular keyboard) now sets the associated day to be the “first day of the week”.
The datePicker can be controlled using the keyboard in the following scenarios:
Inline datePickers
Inline datePickers are automatically placed into the document tab order – which means that they can “have focus”.
Once focused (i.e. the user has tabbed to the datePicker control), they can be controlled using the keyboard.
Popup datePickers
Should the datePickers associated “button” be activated using the keyboard (i.e. by focusing on the button and then pressing Enter), the datePicker will be keyboard responsive.
Should the button be activated by a mouse click, the datePicker will launch without active keyboard controls.
ARIA Roles & Properties
The following ARIA Roles have been set for the datePicker:
| Role | Associated HTML element |
|---|---|
| grid | Assigned to the TABLE |
| gridcell | Assigned to all TD nodes |
| row | Assigned to all TR nodes within the TBODY |
| columnheader | Assigned to all of the TH nodes representing the day of the week |
| rowheader | Assigned to all of the week number TH nodes (if present) |
| button | Assigned to a popup datepickers activation button |
The following ARIA Properties have been set for the datePicker:
| Property | Associated HTML element |
|---|---|
| hidden | Assigned to the wrapper DIV for all invisible popup datePickers, the first two TR nodes within the THEAD (used to display the day & month and navigation buttons) and disabled datePickers and activation buttons. |
| selected | Assigned to the currently selected dates TD node |
| describedby | If the “describedby” global configuration parameter has been set, then this is used to set the describedby relationship |
| labelledby | If the associated form element has a label, the label is used to set the “labelledby” relationship |
| haspopup | Assigned to a popup datepickers activation button |
| disabled | Assigned to a disabled datePicker |
Callback functions
The following callback events are available:
- datereturned
- Called everytime the script updates the associated form element(s) value
- dateset
- Called before the datePicker updates the currently selected value – this is called whenever the associated form elements onchange event fires or a date has been selected using the datePicker
- redraw
- Called whenever a datePicker updates the U.I.
- domcreate
- Called whenever the datePicker is added to the DOM
- dombuttoncreate
- Called whenever a popup datePickers activation button is added to the DOM
Stipulating callback functions is as easy as adding a “callbackFunctions” parameter to the initialisation Object and setting its value to be itself an Object of key/value pairs – where the key names one of the available callbacks and the associated value is an Array of functions to call.
A pseudocode example of this is shown below:
var opts = {
formElements:{"inp1":"%d/%m/%Y"},
// Stipulate some callback functions
callbackFunctions:{
"redraw":[function1, function2, ... functionN],
"dombuttoncreate":[function1, function2, ... functionN]
}
};
datePickerController.createDatePicker(opts);
Callback function arguments
All callback functions are passed a Javascript Object containing information on the status of the datePicker itself – this is detailed below:
// All callback functions receive the following Object...
{
"id": [the ID of the first form element stipulated within the initialisation object],
"date": [a Javascript Date Object representing the selected date or NULL if no date is selected],
"dd": [the date part of the selected date or NULL if no date is selected],
"mm": [the month part of the selected date or NULL if no date is selected],
"yyyy": [the year part of the selected date or NULL if no date is selected],
// NOTE: only the "redraw" callback gets the following additional parameters
"firstDateDisplayed": [a String representing the YYYYMMDD value of the first date shown],
"lastDateDisplayed": [a String representing the YYYYMMDD value of the last date shown]
}
Additionally, the “redraw” callback can return a Javascript Object that stipulates classNames to add to specific dates. For example, the following Object, when returned from the “redraw” callback function, will add the class “santa” to the TD that represents Christmas day 2009:
{
20091225:"santa"
}
All dates should be stipulated in a YYYYMMDD format within the returned Object.
The Javascript A.P.I
The datePickerController Object has a slew of public methods. These are described below:
| Method | Description |
|---|---|
setDebug(Boolean) |
Accepts a Boolean value that, when set to true, will make the script throw Javascript errors should a problem occur. When set to false, the script should silently fail whenever an error occurs. |
addEvent(obj, type, fn) |
A classic addEvent function (just in case you need one) |
removeEvent(obj, type, fn) |
A classic removeEvent function |
show(inputID) |
Makes a popUp datePicker associated with a form element having an ID of “inputID” appear (fade in) |
hide(inputID) |
Makes a popUp datePicker associated with a form element having an ID of “inputID” dissappear (fade out) |
destroyDatePicker(inputID) |
Removes the datePicker associated with the form element having an ID of “inputID” from the DOM (and browser memory) |
cleanUp() |
Loops through the current list of in-memory datePickers and checks to see if their associated form element(s) exist within the DOM; if not, the datePicker is itself removed from the DOM (and browser memory). |
printFormattedDate(dt, fmt, useImportedLocale) |
Accepts three arguments, a Javascript Date Object, a date format String and a Boolean value (that instructs the script to use the imported locale or default to using the English locale). Returns a String. |
setDateFromInput(inputID) |
Instructs the datePicker associated with the form element having an ID of “inputID” to update its currently selected date by parsing the associated form elements value. Usefull should you use Javascript to change the value of the form element in question. |
setSelectedDate(inputID, yyyymmdd) |
Instructs the datePicker associated with the form element having an ID of “inputID” to update its currently selected date to the “yyyymmdd” value passed as an argument. If the setting of the date is successfull, the associated form element values will be updated to reflect the new date. It is also possible to pass a JS Date Object as the second parameter. |
setRangeLow(inputID, yyyymmdd) |
Accepts two arguments, a String representing the associated form element ID and a second String representing either a YYYYMMDD date format String or a JS Date Object. |
setRangeHigh(inputID, yyyymmdd) |
Accepts two arguments, a String representing the associated form element ID and a second String representing either a YYYYMMDD date format String or a JS Date Object. |
parseDateString(str, format) |
Accepts two arguments, the first a fully formed date String (e.g. “13th March 1970”) and the second, a date format String that the first argument is parsed against. Returns a Javascript Date Object on success or FALSE on failure. |
setGlobalOptions(JSON) |
Explained in more detail within the section Setting Global configuration parameters. |
dateValidForSelection(inputID, date) |
Accepts two arguments, a String representing the associated form element ID and a Javascript Date Object. Returns a Boolean value indicating whether the date is valid for selection or not i.e. within the date ranges and not disabled etc |
getSelectedDate(inputID) |
Accepts one argument, a String representing the associated form element ID. Returns a JavaScript date Object if the datePicker has a currently set date or FALSE if not. |
setBespokeTitles(inputID, titles) |
Accepts two arguments, a String representing the associated form element ID and an Object containing keys of the form “YYYYMMDD” and a String as the key’s associated value e.g. { 20091225:“Christmas Day” }. Calling this function will reset all currently set bespoke titles for the datePicker. Wildcards are accepted within the date Strings. |
addBespokeTitles(inputID, titles) |
Accepts two arguments, a String representing the associated form element ID and an Object containing keys of the form “YYYYMMDD” and a String as the keys associated value e.g. { 20091225:“Christmas Day” }. Calling this function will add the new messages to the list of current messages already present for the datePicker. Wildcards are accepted within the date Strings. |
setDisabledDates(inputID, dts) |
Accepts two arguments, a String representing the associated form element ID and an Object of “YYYYMMDD” value pairs to disable. Calling this function will reset all currently disabled dates for the datePicker. Wildcards are accepted within the date Strings. |
addDisabledDates(inputID, dts) |
Accepts two arguments, a String representing the associated form element ID and an Object of “YYYYMMDD” value pairs to disable. Calling this method will add the dates to the list of currently disabled dates. Wildcards are accepted within the date Strings. |
setEnabledDates(inputID, dts) |
Accepts two arguments, a String representing the associated form element ID and an Object of “YYYYMMDD” value pairs to enable. Calling this function will reset all currently enabled dates for the datePicker. Wildcards are accepted within the date Strings. |
addEnabledDates(inputID, dts) |
Accepts two arguments, a String representing the associated form element ID and an Object of “YYYYMMDD” value pairs to enable. Calling this method will add the dates to the list of currently enabled dates. Wildcards are accepted within the date Strings. |
disable(inputID) |
Disables the datePicker associated with the form element having an ID of “inputID” (and, if necessary, the datePickers activation button) and stops all mouse and keyboard interaction with the datePicker. |
enable(inputID) |
Enable the datePicker (and, if necessary, the datePickers activation button) and re-enables all mouse and keyboard interaction. |
createDatePicker(options) |
Creates a datePicker using the options Object passed in as an argument. |
| dateToYYYYMMDDStr(date) | Returns a YYYYMMDD date format String from the JS Date Object passed as an argument. |
For example, to use the cleanUp method, you would use the following Javascript:
datePickerController.cleanUp();
Bugs and foibles
The inevitable list of known cross-browser foibles:
Internet Explorer
The accessibility enhancements make the U.I. sluggish in Internet Explorer, whose Javascript engine isn’t as fast as other A-Grade browsers, when viewed on an older PC.
The current CSS file is untested in IE6 and, until further notice, should be treated as a work in progress.
Opera
Opera adds a non-customisable “focus” outline to each TD node which encapsulates the hidden span elements within the TD. This makes the focus outline in Opera stretch beyond the left hand side of the viewport and actually hinders accessibility for people with low vision.
To stop this happening, I currently don’t add the hidden text in Opera. If anyone can show me a better, non-problematic method for hiding the text (whilst still making it available to screen readers) that does not incur the wrath of the Opera focus outline I’d be happy to hear it.
The License
The script is now released under a double MIT/GPL2 license. Should you use the script within a commercial context (or are feeling generous today), please think about clicking the payPal donate button below – it’s certainly not an obligation but it would most certainly put a smile on my face and perhaps goad me into maintaining the script on a regular basis.
If you require another license, just ask politely.
Demo, downloads and updates
View the updated date-picker demos or head over to github to download the latest source.

Previous Comments ~
is there a way to hide the year or the day portion of the calendar (even if it still is present on output). this would be very useful for situations where a day in a month of an arbitrary year is needed, or for picking a month without caring about the day.
failing that a is there a way to specify a skin to use? I could make a skin that hides those parts myself if there was a way to load a different skin for different instances of the calendar.
failing that is there a way to specify the id or add a class name to the main element of the calendar? I’m sure you can see where I am going with that.
Before I go into my more complicated problem, I should point out a small error I noticed: setGlobalVars() doesn’t exist, it’s setGlobalOptions()
I’m having some trouble setting a language to use.
Method 1: Creating a JSON Object between the script tags doesn’t work.
Method 2: Using setGlobalOptions(MyJSONObject) after calling the script doesn’t work.
Note that the above two work just fine for something like “nodrag”, it only seem to fail with languages (though I haven’t tried everything).
Method 3: Calling the language script just before the datepicker script. This actually works, but it also throws out an error in FireBug, “datePickerController is not defined.” This is in the try-catch at the bottom. Obviously this doesn’t cause any serious problems, but it’s pretty annoying for a developer. The problem seems to solved by calling the language script AFTER the datepicker script.
I made a little hack in the library for my purposes
if(this.styleClass) this.div.className += ‘ ‘+this.styleClass;
it got the job done, I don’t know if there would be any side effects from this and I would like not to fork from the official version, but this trivial line allows per calendar skinning and therefore skins where the year or days are hidden.
@Bobboau – I shall try to add the styleclass hack to the main code as it’s a good idea.
@Ryan – Looks like you spotted a bug (or two). I’ll have a look this weekend.
I also added this:
http://pastebin.com/2Y4viEQc
to allow changing it at runtime. I also added getters and setters to the datePickerController. It seems to be working well, but there are probably better ways to do it. for instance, if you were to set the styleclass to ‘date-picker’ and then change it to something else, that would probably be ‘bad’. there are probably other internally used class names that should at the very least result in some sort of error or exception if you try to use them that i didn’t notice.
BTW I think there might be an issue with the internal dateToYYYYMMDD() function, at least in firefox (7.0.1, 64 bit ubtuntu 11.10) it fails at
typeof dt == “date”
because Date objects return typeof object, I think what you want there is
dt instanceof Date
P.S. sorry for the double post, I wish i could edit comment rather than posting multiple times
(I should make sure I don’t have anything else on my mind before I hit that submit button)
just found something, it seems ether daysInMonth or parseDateString has an off by one error. you are parsing out the month, and using it as a index into an array, the array is 0 based, but the month number from the string starts at one. I am assuming the error is in the parsing side of this, otherwise you would have the wrong number of days in the presented calendar.
whatever the case, parseDateString fails on ’2011-10-31’ with a format of ‘%Y-%m-%d’
not accept “16/10/2011” in “%d/%m/%Y” date format. have solution? tanks!
Hi, thanks for this update, I was about to report a bug with the v5 version, but it seems fixed in this one. If I clicked on a date a month or more out, clicking the Today or month-back button did nothing, but the new code works fine.
One problem I am having, though, on both the v5 and v6, is a CSS issue, on my page the future dates are colored white on a white background. Weekend dates are colored, past dates in grey, hovered date in darker grey. I haven’t isolated a simple test case to figure exactly why this is, but I’ve gotten around it by adding ‘color: #646464;’ to the CSS in the .date-picker table block starting at line 98. This correctly sets a default color to correct my issue.
First off thanks, this is great.
My problem is when I hit refresh, it keeps the last selected date instead of the default I set using the cursorDate parameter. Is there a way to prevent this behavior?
you could set the date explicitly in the page’s onload handler.
I have a feeling that is not the calendar but the control it is connected to retaining it’s value between page loads, some browsers do that.
@Ryan I’ve fixed a bug dealing with passing the “lang” parameter in JSON (within the script tags) and updated all language files to not throw warnings in the console.
@Bobboau The daysInMonth bug has been fixed and instanceof used instead of typeof (duh!)
@Rafael The bug has been fixed and the date parses correctly now.
@Jim Wright A default text colour has been added to the CSS file. Well spotted.
@Craig Mouser The script goes out of its way to handle this situation (how browsers update the form element value from cache). There’s no way to avoid the functionality I’m afraid – it’s a browser “feature” and no two browsers do it the same way!
where are the images loaded from? I need to deploy my application in an environment where there is no internet access. I see that all the image URLs are base64 encoded.
Hi, thanks for this great date picker plugin. It’s really professional.
I had a question: I have two input text boxes which require the date picker viz. start date and end date. How do I initialize both of them with just one createDatePicker() call?
Thanks.
@Rajesh: As the images are stored in the CSS file itself (last point in the At a Glance section), you don’t have to worry about the images.
my team has noticed some interesting behavior, and we are not sure if it is in the library or our code, but it seems that when a date picker is loaded with a date when there is not that date in the next month (i.e. 1/30/2011, because 2/30/2011 does not exist) sometimes it fails to load the date correctly and the format string is presented. this seems to be a race condition, and is more prevalent on IE, though it still shows up (intermittently) in firefox
I don’t know if this is still relevant but I just want to report a bug on datePicker v4.3. When changing the “First Day of the Week” using the keypad, the headers do not update. As a quick fix, I added a call to o.updateTableHeaders() on line 134.
I’m back, found a bug/feature request. When initializing the datePicker, you cannot use a variable for the id. If I hard code a string it will work. But if I create the string in a variable and put it in there it will not work.
Hi there,
First of all I would like to say this is one of the best javascript datepickers on the web today. It’s also very flexible.
But now the thing is the currunt version and also the demo version is not working in IE. Not in IE7,8 and 9. The icon is not showing up.
Could you let me know how to fix this? Hopefully on short notice because i have a deadline this week and would really like to implement your datepicker as it’s one of the best out there as i stated earlier.
Looking forward to your answer.
Best Regards,
Frank
Back again with a question;
I can’t find to seem a way to disable all the dates in the past? I tried multiple thing like:
datePickerController.setDisabledDates(“demo-3”, { “********”: “20111125” }); or
datePickerController.setDisabledDates(“sf-date”, { 1: “20111125” });
Could you please let me know how to do this? And wouldn’t it be great if there is just a simple setting to disable all past dates?
Thanks in advance.
Frank
Kudos to the work that you have done.
1 quick question.
Can the date picker pop-up be invoked when the text box where the date is to be displayed gets the focus? If no, do you think there is a quick hack to do this?
Cheerz
Hi there.
Back again with a comment and/or maybe a bug. It seems that the hideInput setting works ONLY when the staticPos is set to true? Is this the intended functionality or a bug?
A comment for Frank: To disable past dates, RTFM, or just use setRangeLow(inputID, yyyymmdd) with the current date as the date.
Hi Tver3305,
Thanks for the tip. I already sorted this one out after searching a long time ;) I RTFM but think I missed it the first time.
Does the datepicker works in IE in your project? Here it does not work at all…
Let me know so I know if it’s because of something I did or if it’s in the sourcecode.
Thanks in advance.
If someone has the problem that the datepicker is not working in IE, this is fixed in the latest version of the datepicker. I just found out by checking Github. This issue was resolved yesterday (dec 5th) by the author but I think Brian forgot to mention it here on the comment section ;)
Thanks Brian for the fast fix.
How do you get the datepicker to show up in a modal window?
@Craig Mouser:
I have the creation of a few date pickers in a loop and do it like this:
http://pastebin.com/kjbcT1Bx
I use the date pickers in an AJAX dialog which loads data based on the actual page and can be reloaded multiple times and I was having a problem with the datePickers stomping on each other. That’s what the bit about destroying is for. Once I did that, I haven’t had any problems.
If anyone is having problems with the onchange event of the form element not firing, I got around it by using the dateset callback. I have my own hooks into onchange to do change tracking (ie, not allowing a dialog to close if there are pending changes), but they weren’t working when changing a date via the datePicker. I fixed it by using callbackFunctions:
https://gist.github.com/1444655
Note: this is based on Prototype (not that it matters..just trying to avoid any possible confusion).
Thanks for your great work.
I’m trying to incorporate the datepicker into a dynamic repeating table but I’m having some issues. Any guidance or experience? See the link for my problem in detail.
http://stackoverflow.com/questions/8564749/dynamic-table-with-multiple-datepickers
Sorry if someone already commented on this. The example under “Disabling date selection” above is missing the first paramater in the setDisabledDates function.
Thanks for a great datepicker!
hi is there a example on how to change the rangelow for another field, lets say #endDate upon #startDate change??
Comments are currently closed but feel free to contact me on twitter with your questions or suggestions - I’d love to hear from you.