The AccDC Technical Style Guide is designed to provide reliable and consistent interaction designs that are accessible to the highest percentage of people possible, and to establish a baseline for Functional Accessibility that can be utilized, built upon, studied, and tested against.
AccDC was awarded the "Above and Beyond Accessibility Award" from the United States Department of Labor, and was presented at the Developing with Accessibility Event, hosted by the Federal Communications Commission in Washington DC in 2012.
Functional Accessibility means that each component is fully accessible from the keyboard, with or without a screen reader running.
All of the AccDC Technical Style Guide design patterns have been fully tested for maximum accessibility using all of the following combinations:
AccDC Technical Style Guide Mirrors:
Please address any direct questions to Bryan Garaventa, or to the Accessible Innovators Group for community support.
AccDC is a JavaScript based Application Programming Interface (API) that can be used with other libraries and frameworks, or by itself, to create new or enhance pre-existing web technologies with accessible features.
This is accomplished by utilizing the AccDC API properties and methods, and by leveraging the features that are available within all instantiated AccDC Objects.
The primary purpose of the AccDC API, is to recursively process AccDC Objects, which are rendered as encapsulated dynamic content components.
The majority of AccDC API properties and methods are prototyped within every AccDC Object, making every AccDC Object fully autonomous and programmatically configurable using JavaScript.
This is how AccDC Objects can dynamically control the behaviors of other AccDC Objects at runtime.
An AccDC Object is literally an instantiated JavaScript Object, which stores all relevant data and AccDC API properties and methods within it.
The shell construct of an AccDC Object declaration is as follows:
var myObjArray = [
{
id: 'uniqueObjectId',
role: 'Object Role Name'
// Other AccDC API property and method declarations go here...
}
];
The array of AccDC Object declarations is passed as a parameter to the $A() function, which instantiates them as registered AccDC Objects.
$A(myObjArray);
All instantiated AccDC Objects are then registered within the $A.reg associative array, which can be queried directly using the ID of each AccDC Object in order to reference, configure, and control specific objects using JavaScript.
Example:
var dc = $A.reg['uniqueObjectId'];
Or
var dc = $A.reg.uniqueObjectId;
An instantiated AccDC Object can then be programmatically configured by modifying or invoking properties and methods within the object instance.
Examples:
// Set literal content to be rendered
dc.source = 'Hello World';
// Set the body as the container insertion point
dc.isStatic = 'body';
// Prepend the rendered content to the body content instead of replacing
dc.prepend = true;
// Set a top level class name for the newly rendered container Div element
dc.className = 'banner';
dc.runAfter = function(dc){
// Do something after the content finishes loading
};
// Render the new content
dc.open();
Alternatively, all of the above property and method declarations can be included within the object literal declaration, before the object array is passed to the $A() function.
Example:
var myObjArray = [
{
id: 'uniqueObjectId',
role: 'Object Role Name',
source: 'Hello World',
isStatic: 'body',
prepend: true,
className: 'banner',
runAfter: function(dc){
// Do something after the content finishes loading
},
runAfterClose: function(dc){
// Do something after the content finishes closing
},
// Render the object immediately
autoStart: true,
// Automatically announce the rendered textual content for screen reader users
announce: true
}
];
// Then register the object array
$A(myObjArray);
All AccDC API properties and methods are applicable to AccDC Objects, and are confined within the scope of that object.
To learn about sibling and global overrides for AccDC Objects, view the details about the $A() function within the AccDC Core API documentation.
AccDC Objects can also be used to store specific data that relates only to that object, which can then be accessed by other AccDC Objects.
Example:
// Save data within one AccDC Object
dc.tmp = {
form: formElement
};
// Then access the data from another AccDC Object or process
var dataString = serialize( $A.reg.uniqueObjectId.tmp.form.elements );
All data stored within an AccDC Object remains within the object, even after the "close()" method is used to close the object and remove its content from the DOM.
Only the "$A.destroy()" method will completely destroy an AccDC Object and all of its stored data.
All of the Accessible Component Modules tap into this functionality by interfacing with the AccDC API.
If, for some reason an AccDC Object is not rendering properly when the open() method is invoked, Debugging Mode can be used to diagnose the cause of the issue.
Example:
// Enable Debugging Mode $A.fn.debug = true;
When set to true, this will throw an alert with specific instructions if the issue is caused by a lack of or improper combination of AccDC API properties.
Debugging Mode is set to false by default.
Currently there are four versions of the AccDC API available:
Since all Accessible Component Modules plug into the AccDC API, the same module code will work correctly in all AccDC API versions equally.
Example using the Standalone, jQuery, or MooTools AccDC versions:
<head> <!-- If using the AccDC jQuery or MooTools extension, load jQuery or MooTools here first. --> <script type="text/javascript" src="Acc.DC.API.js"> // Load AccDC, which will create the $A namespace </script> <script type="text/javascript" src="module_name.js"> // Load as many of the Accessible Component Modules as desired, // which will add them to the $A namespace. </script> <script type="text/javascript" src="setup.js"> // Then load the setup script to invoke module functionality after the page finishes loading. </script> </head>
Example using Dojo:
<head> <script type="text/javascript" src="dojo/dojo.js" data-dojo-config="async:true"> // Load Dojo asynchronously. </script> <script type="text/javascript"> // Configure AccDC modules and scripts to be loaded synchronously for flow control InitAccDC = [ 'module1.js', 'module2.js' ]; // Now load the AccDC API using the Dojo AMD Loader // The referenced AccDC API file is located at dojo/acc.dc.api.js require(['dojo/acc.dc.api']); </script> </head>
This will set up AccDC, and load all of the declared modules into the $A namespace, ready for use within your web application.
If the AccDC Bootstrap module is also loaded, then there is no need to include a setup script.
All configurations are controlled through HTML5 attributes within the markup and by editing the "accdc_bootstrap.js" file as desired to customize functionality.
When the Bootstrap Module is executed, it parses the newly loaded DOM, recognizes class names that correspond with specific Accessible Component Modules, then configures and invokes the specified module using HTML5 attributes within the markup to customize both output and behavior.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
To enable this functionality, simply load the AccDC Bootstrap module after all of the desired Accessible Component Modules have been loaded.
Example using the Standalone, jQuery, or MooTools AccDC API versions:
<head> <!-- If using the AccDC jQuery or MooTools extension, load jQuery or MooTools here first. --> <script type="text/javascript" src="Acc.DC.API.js"> // Load AccDC, which will create the $A namespace </script> <script type="text/javascript" src="module_name.js"> // Load as many of the Accessible Component Modules as desired, // which will add them to the $A namespace. </script> <script type="text/javascript" src="accdc_bootstrap.js"> // Then load AccDC Bootstrap to parse the DOM automatically </script> </head>
Example using Dojo:
<head> <script type="text/javascript" src="dojo/dojo.js" data-dojo-config="async:true"> // Load Dojo asynchronously. </script> <script type="text/javascript"> // Configure AccDC modules and scripts to be loaded synchronously for flow control InitAccDC = [ 'module1.js', 'module2.js', // Then load AccDC Bootstrap to parse the DOM automatically 'accdc_bootstrap.js' ]; // Now load the AccDC API using the Dojo AMD Loader // The referenced AccDC API file is located at dojo/acc.dc.api.js require(['dojo/acc.dc.api']); </script> </head>
Some modules refer to offscreen text, which can be used to provide textual information for screen reader users that is not displayed visually and has no impact on visual layout.
The following CSS class has been proven to work well for this purpose, which is the same that is built into AccDC as the "$A.sraCSS" object.
.offscreenText {
position: absolute;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
padding: 0;
border: 0;
height: 1px;
width: 1px;
overflow: hidden;
z-index: -1000;
}
This styling configuration is based on the research done by Thierry Koblentz, which is more fully described at
https://developer.yahoo.com/blogs/tenydnblog/clip-hidden-content-better-accessibility-53456.html
IMPORTANT: All of the HTML markup syntax examples found within the expandable Accessible Component Module sections represent the minimal code necessary for using the associated JavaScript module included with the AccDC API, though the actual markup is flexible when implemented.
Since the associated JavaScript module handles key attributes such as tabindex, amongst relevant ARIA state and property attributes, these are not included within the HTML markup syntax examples, since assigning these manually would complicate the scripting setup process for each module.
To see how tabindex and relevant ARIA attributes are handled, use a DOM viewer utility to examine the rendered output of each live demo within the Coding Arena, where dynamic behaviors can be observed.
Accordions are a fairly simple control type that are easy to make accessible.
Though similar in both concept and execution to Tab Controls, they are not the same.
A Tab Control has a series of grouped triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element group when opened. The container element insertion point for all Tab Control triggering elements is shared between them. Also, the group of triggering elements in a Tab Control has only one tab stop. The arrow keys are then used to switch focus between each Tab, and the Enter or Space key is used to expand the desired Tab content panel.
In contrast, an Accordion has a series of triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element when opened. The container element insertion points for Accordions are not shared. Also, all Accordion links appear in the tab order. The reason why ARIA attributes such as role="tablist" and role="tab" are not included within accordions, is because the insertion of inline content would place dynamic content sections within the same Tablist container, making it impossible to determine the order of nested Tab controls when present within the inserted content.
The chosen implementation should always match the UI that it's being applied to, to prevent confusion.
The Accordion Module automates these processes by adding all related event handlers and managing all related rendering procedures.
Referencing external content:
<div class="accordionGroup"> <a href="#" class="accAccordion" data-src="files/accordions.html#containerId1" data-insert="sectId1" data-defaultopen="true" id="accordionId1"> Triggering Element One Name </a> <div id="sectId1"><!-- (accordionId1 content will be inserted here when opened) --></div> <a href="#" class="accAccordion" data-src="files/accordions.html#containerId2" data-insert="sectId2" id="accordionId2"> Triggering Element Two Name </a> <div id="sectId2"><!-- (accordionId2 content will be inserted here when opened) --></div> </div>
Or referencing internal content:
<div class="accordionGroup2"> <a href="#" class="accAccordion" data-internal="containerId1" data-insert="x-sectId1" data-defaultopen="true" id="x-accordionId1"> Triggering Element One Name </a> <div id="x-sectId1"><!-- (x-accordionId1 content will be inserted here when opened) --></div> <a href="#" class="accAccordion" data-internal="containerId2" data-insert="x-sectId2" id="x-accordionId2"> Triggering Element Two Name </a> <div id="x-sectId2"><!-- (x-accordionId2 content will be inserted here when opened) --></div> </div>
HTML5 "data-" attributes are used to configure specific functionality for each accordion expand/collapse link. These include the following:
Required attributes:
Important: The insertion point where accordion content is rendered must be inline with (meaning directly after) the triggering element, to ensure accessibility for screen reader and keyboard only users. (No other active elements or page content should separate them.)
The examples above use DIV tags as container elements, but it doesn't really matter what the container element is, as long as the IDs match up. For instance, the interactive samples in the Coding Arena use DL tags as the main container, DTs to hold the triggering element, and DDs to act as the insertion points, which works well and is easy to format.
Container Element HTML Syntax
<div id="containerId1"> Accordion panel 1 content goes here. </div> <div id="containerId2"> Accordion panel 2 content goes here. </div>
$A.generateAccordion( 'div.accordionGroup a.accAccordion' , {
// Configuration key / value mappings
}, document , callbackFunction(dc){
// Run every time an accordion expand/collapse link is toggled
// 'dc' is the registered Accordion AccDC Object
// dc.triggerObj is the triggering element
// dc.containerDiv is the DOM node where all accordion panel content is rendered
// dc.loaded reflects whether the accordion panel is currently open
} );
The first parameter is a CSS Selector that specifies all accordion expand/collapse links that are part of the same accordion group.
If multiple accordions are present on the same page, each accordion should be declared separately using the above statement, and the CSS Selector should only reference the expand/collapse node links that apply to that particular accordion, and to no other.
The reason for this is simple. When an accordion is active, it will close all open accordion nodes when an expand link is activated. So if you don't want all of the nodes of every other accordion on the page to be closed at the same time as well, then you should separate them using unique CSS Selectors for each group.
The second parameter is used to configure accordion functionality using key / value map overrides.
Example:
{
// Set the hidden text role and state that will be added to the triggering element for screen reader users
accordionRole: 'Accordion',
accordionState: 'Expanded',
// Set the accordion AccDC Object to render literal content
// (only when pulling content from within the same page, remove otherwise)
mode: 0,
// Preload HTML markup to speed rendering
// (only when pulling content from an external page, remove otherwise)
preload: true,
// Preload images to speed rendering
// (only when pulling content from an external page, remove otherwise)
preloadImages: true,
// Set the class name that will be added to the triggering element of the currently open accordion
toggleClass: 'open',
// Choose whether or not to make accordion expand/collapse links toggles as well
isToggle: false
// Additional AccDC API properties and methods may be applied here as well if desired.
}
The third parameter (contextDOM_Node) specifies the container DOM node where the accordion is contained, which confines the CSS Selector to the contents of this node. This can also be used to reference accordion groups contained within iFrame documents.
The fourth parameter is a callback function that can be used to configure additional functionality whenever an accordion is opened or closed.
Every accordion node is registered as an AccDC Object, the ID of which matches the ID attribute value on the accordion expand/collapse link. For this reason, all accordion expand/collapse links must have unique ID attribute values.
This means that you can programmatically control each accordion node using JavaScript if desired, like so:
// Get a reference to the accordion AccDC Object for the accordion expand/collapse link with id="uniqueId" var dc = $A.reg['uniqueId']; // Now invoke the object dc.open(); // Or close it dc.close(); // All other AccDC API properties and methods can be applied here as well.
Regarding the triggering element for expand/collapse links, you should always use an active element for this purpose to ensure accessibility for both screen reader and keyboard only users.
Within the Coding Arena samples, these are standard links (A tags with an Href attribute), which includes a SPAN tag with a changeable background image. However, you can use whatever type of triggering element you wish, a standard link, button, or image link, with any type of styling. There must be an active element as a triggering element though, to ensure accessibility.
The sample accordions in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the accordion. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled accordion will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The accordions within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accAccordion", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes for the triggering element:
Tabs are a fairly simple control type that are easy to make accessible.
Though similar in both concept and execution to Accordions, they are not the same.
An Accordion has a series of triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element when opened. The container element insertion points for Accordions are not shared. Also, all Accordion links appear in the tab order. The reason why ARIA attributes such as role="tablist" and role="tab" are not included within accordions, is because the insertion of inline content would place dynamic content sections within the same Tablist container, making it impossible to determine the order of nested Tab controls when present within the inserted content.
In contrast, a Tab Control has a series of grouped triggering elements that expand and collapse, the rendered content of which is inserted directly after the triggering element group when opened. The container element insertion point for all Tab Control triggering elements is shared between them. Also, the group of triggering elements in a Tab Control has only one tab stop. The arrow keys are then used to switch focus between each Tab, and the Enter or Space key is used to expand the desired Tab content panel.
The chosen implementation should always match the UI that it's being applied to, to prevent confusion.
The Tab Module automates these processes by adding all related event handlers and managing all related rendering procedures.
Referencing external content:
<div role="tablist" id="tabList1"> <div> <a href="#" class="accTab" data-src="files/tabs.html#containerId1" data-insert="tabPanelId" data-defaultopen="true" id="tabId1" role="tab"> <span>Triggering Element One Name</span> </a> </div> <div> <a href="#" class="accTab" data-src="files/tabs.html#containerId2" data-insert="tabPanelId" id="tabId2" role="tab"> <span>Triggering Element Two Name</span> </a> </div> </div> <div id="tabPanelId"><!-- (All Tab panel content will be inserted here when a Tab is opened) --></div>
Or referencing internal content:
<div role="tablist" id="tabList2"> <div> <a href="#" class="accTab" data-internal="containerId1" data-insert="tabPanelId2" data-defaultopen="true" id="x-tabId1" role="tab"> <span>Triggering Element One Name</span> </a> </div> <div> <a href="#" class="accTab" data-internal="containerId2" data-insert="tabPanelId2" id="x-tabId2" role="tab"> <span>Triggering Element Two Name</span> </a> </div> </div> <div id="tabPanelId2"><!-- (All Tab panel content will be inserted here when a Tab is opened) --></div>
HTML5 "data-" attributes are used to configure specific functionality for each Tab expand/collapse link. These include the following:
Required attributes:
Important: The insertion point where Tab panel content is rendered must be inline with (meaning directly after) the Tablist group, to ensure accessibility for screen reader and keyboard only users. (No other active elements or page content should separate them.)
The examples above use DIV tags as container elements, but it doesn't really matter what the container element is, as long as the IDs match up. For instance, the interactive samples use standard list markup to group related Tab links, which works well and is easy to format.
Container Element HTML Syntax
<div id="containerId1"> Tab panel 1 content goes here. </div> <div id="containerId2"> Tab panel 2 content goes here. </div>
The following attributes are handled automatically by the Tab Module:
$A.setTabs( 'div.tabGroup a.accTab' , {
// Configuration key / value mappings
}, useARIA? , document ,
function(dc){
// Optional callback to execute after a Tab panel opens
// 'this' is the same as dc.triggerObj, and is the DOM node for the triggering element
// dc.containerDiv is the DOM container node that contains the newly loaded Tab panel content.
} );
The first parameter is a CSS Selector that specifies all Tab expand/collapse links that are part of the same Tablist group.
If multiple Tablist groups are present on the same page, each Tablist should be declared separately using the above statement, and the CSS Selector should only reference the expand/collapse node links that apply to that particular Tablist, and to no other.
The reason for this is simple. When a Tab panel is opened, it will close all other Tab panels when an expand link is activated. So if you don't want all of the nodes of every other Tablist group on the page to be closed at the same time as well, then you should separate them using unique CSS Selectors for each group.
The second parameter is used to configure Tab functionality using key / value map overrides.
Example:
{
// Set the Tab panel boundary text that will be conveyed to screen reader users
role: 'Tab',
accStart: 'Start',
accEnd: 'End',
// Set the Tab AccDC Object to render literal content
// (only when pulling content from within the same page, remove otherwise)
mode: 0,
// Preload HTML markup to speed rendering
// (only when pulling content from an external page, remove otherwise)
preload: true,
// Preload images to speed rendering
// (only when pulling content from an external page, remove otherwise)
preloadImages: true,
// Set a className that will be added to the triggering element for the currently active tab
toggleClass: 'active',
// Choose whether or not to make Tab expand/collapse links toggles as well
isToggle: false
// Additional AccDC API properties and methods may be applied here as well if desired.
}
The third parameter (useARIA?) is a Boolean (true or false), that specifies whether the Tab Control will be configured as an ARIA Tab widget.
If true, role="tablist" and role="tab" must be present within the markup in the correct locations.
If false, role="tablist" and role="tab" must not be included within the markup.
Important: The ARIA attributes role="tablist" and role="tab" must only be used on client side widgets that don't require a page refresh or navigate to another page.
The reasons why are fully discussed in the article at http://lnkd.in/5nPudh
The fourth parameter (contextDOM_Node) specifies the container DOM node where the Tablist markup is contained, which confines the CSS Selector to the contents of this node. This can also be used to reference Tab groups contained within iFrame documents.
The fifth parameter is a callback function that can be used to configure additional functionality whenever a Tab panel finishes rendering.
Every Tab panel is registered as an AccDC Object, the ID of which matches the ID attribute value on the Tab expand/collapse link. For this reason, all Tab expand/collapse links must have unique ID attribute values.
This means that you can programmatically control each Tab panel using JavaScript if desired, like so:
// Get a reference to the Tab AccDC Object for the Tab expand/collapse link with id="uniqueId" var dc = $A.reg['uniqueId']; // Now invoke the object dc.open(); // Or close it dc.close(); // All other AccDC API properties and methods can be applied here as well.
Regarding the triggering element for expand/collapse links, you should always use an active element for this purpose to ensure accessibility for both screen reader and keyboard only users.
Within the Coding Arena samples, these are standard links (A tags with an Href attribute). However, you can use whatever type of triggering element you wish, a standard link, button, or image link, with any type of styling. There must be an active element as a triggering element though, to ensure accessibility.
If using an image link however, the IMG tag must have a null Alt attribute (alt="") to hide it from screen reader users, and offscreen text must be included if no visible screen text is present. This will ensure the highest level of accessibility for the highest percentage of screen reader users across all platforms.
The sample Tabs in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the Tablist. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled Tablist will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The Tablists within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accTab", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes for the triggering element:
As an ARIA widget implementation, the Tablist container element must include the attribute role="tablist", and all Tab item links must include the attribute role="tab" to ensure accessibility for screen reader users.
Both the Tablist container element and all Tab item links must include unique ID attribute values.
The innerHTML for each Tab item link must contain a textual label, which may be positioned offscreen to hide it visually if desired. (This textual label is necessary so that screen reader users will be able to identify the purpose of the node, and also to ensure proper feedback in iOS devices when using VoiceOver.)
Images may also be used within Tab item links if desired, however, they must include the attribute alt="" to hide them from screen reader users.
To add tooltips for sighted users, use the Title attribute instead, and make sure that the tooltip text matches the text contained within the textual label if positioned offscreen to hide it visually.
ARIA Comboboxes are used to trigger dynamic lists of related options, such as with auto-suggest filters and custom dropdowns.
Expected behaviors:
The ARIA Combobox Module automates these processes by adding all related event handlers.
The HTML syntax varies depending on which type of implementation is desired.
Editable Input
<input role="combobox" type="text" title="Explicit label text" />
Readonly Input
<input role="combobox" type="text" readonly title="Explicit label text" />
Simulated Active Element
<span title="Explicit label text" role="combobox" tabindex="0" class="focusableElement" > <span class="childContainerToUpdate"></span> </span>
All Combobox controls are bound to a standard Select element instance, which may be hidden within the page using CSS, or dynamically generated using JavaScript to support dynamic population via AJAX.
<select name="control-name"> <option value="value-1"> Value 1 name </option> <option value="value-2"> Value 2 name </option> <option value="value-3"> Value 3 name </option> </select>
To set a default value for the Combobox other than index[0], add the 'selected' attribute to the default option.
The following attributes are handled automatically by the Combobox Module:
// Create a new Combobox instance and bind the relevant elements var myCombobox = new $A.Combobox( selectElementDOM-Node , inputDOM-Node , optionalChildDOM-Node ); // Configure settings here prior to invocation // Then invoke the Combobox for auto-rendering myCombobox.start();
The first parameter is the hidden Select element DOM node that will be bound to the Combobox control.
The second parameter is the focusable role=combobox element that will be bound to the hidden Select element.
The third parameter is the embedded child container element that will be bound to the role=combobox element, which is only applicable if the role=combobox element is not a standard Input or Textarea element.
After a Combobox control is instantiated, the following public properties and methods are available.
Methods:
// Set the listbox to render all Select Options regardless of the current value
myCombobox.setShowAll(Boolean); // Default: False
// Set the listbox to render only Select Options that match the substring value
myCombobox.setSubstringMatch(Boolean); // Default: False
// Set the listbox to render only Select Options that include all of the space delimited words in the current value
myCombobox.setWordMatch(Boolean); // Default: False
// Set the Combobox to automatically display the currently selected value within the hidden Select element onStart
myCombobox.setDefault(Boolean); // Default: True
// Set the currently selected listbox value to automatically be saved when focus moves away from the Combobox control
myCombobox.setAutoComplete(Boolean); // Default: False
// Set the parent/child tag markup structure for the dynamically rendered listbox
myCombobox.setTags({
parentTag: 'ul',
childTag: 'li'
});
// Set dynamic class names
myCombobox.setClassNames({
toplevelClass: 'toplevel-div clearfix', // Top level Div class of Combobox listbox
middleClass: 'middle-div clearfix', // Mid level Div class of Combobox listbox
listboxClass: 'listbox clearfix', // // parentTag class
optionClass: 'option clearfix', // childTag class
activeClass: 'active', // Currently active Combobox listbox option
toggleClass: 'pressed' // Pressed state class of the altTrigger element
});
// Set CSS autopositioning relative to the triggering Combobox element.
// Accepted AccDC API values between 0-disabled-default and 12
// For details, see WhatSock.com > Core API > CSS > .autoPosition
myCombobox.setAutoPosition(Number); // Default: 0
// Set a positive or negative top/left offset to be applied to the autoPosition property calculation
myCombobox.setOffset({
top: Number,
left: Number
});
// Set the number of listbox options to render when displayed
myCombobox.setSize(Number); // Default: 5
// Set a different element to act as an autoPosition focus element instead of the Combobox control
myCombobox.setPosAnchor(alternateDOM-Node); // Will not change the DOM insertion point and reading order
// Set a different element to act as an insertion point and autoPosition focus element instead of the Combobox control
myCombobox.setTargetObj(alternateDOM-Node); // Will change the DOM reading order
// Invoke the Combobox control and apply all saved settings
myCombobox.start();
// Close the Combobox control and pause functionality
myCombobox.stop();
// Manually open the Combobox listbox using all applied settings
myCombobox.open();
// Set a handler to execute every time the Combobox listbox is rendered
myCombobox.onOpen(function(dc){
// this = the Combobox control
// dc = the AccDC Object instance for the Combobox listbox
});
// Manually close the Combobox listbox
myCombobox.close();
// Set a handler to execute every time the Combobox listbox is closed
myCombobox.onClose(function(dc){
// this = the Combobox control
// dc = the AccDC Object instance for the Combobox listbox
});
// Set a toggle control to open or close the Combobox listbox
// Must always be set when implementing readonly Input+type=text elements to ensure sighted mouse and mobile touch device support
myCombobox.setAltTrigger(toggleElementDOM-Node);
// Set a handler to execute every time the toggle altTrigger element is activated
myCombobox.onTriggerChange(function(altTriggerElement, toggleState){
// this = altTriggerElement
// toggleState = true or false
});
// Set a handler to execute every time a new value is saved to the Combobox control
// This will override the default functionality, so the Combobox listbox will need to be closed manually if desired.
myCombobox.onSelect(function(optionName, optionValue, comboboxControl, selectElement){
// this = comboboxControl
// optionName = the visible string for the hidden Select option
// optionValue = the value attribute for the hidden Select option
// comboboxControl = the Combobox control element
// selectElement = the hidden Select element
// Save the new value accordingly
// then return the saved string to prevent auto reopening of the Combobox listbox
return 'saved string';
});
// Manually resynchronize the hidden Select to rebuild available Options for the Combobox listbox
// This can be used to repopulate rendered options after remote API queries via AJAX cause the hidden Select to contain new Options
myCombobox.update();
// Set a string to be announced to screen reader users when the Combobox control receives focus
myCombobox.setPromptText(String); // Default: ''
// Set a name for the offscreen Close link for screen reader users
// Necessary for non-sighted touch screen device users to detect the end of the Combobox listbox when rendered
// To disable the offscreen Close link when needed, pass a null value ("") to the method.
myCombobox.setCloseText(String); // Default: 'Close Popup'
Properties:
// Access the hidden Select element DOM node myCombobox.select // Access the role=combobox element DOM node myCombobox.combobox // Access the dynamically rendered listbox AccDC Object, including all AccDC API properties and methods // View the Core API tab at WhatSock.com for a full index of available AccDC API properties and methods. myCombobox.dc
The samples in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
You can change the styling however you wish to fit the layout of any UI, and the comboboxes will still be accessible to both screen reader and keyboard only users regardless. Simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus.
An ARIA Data Grid is one of the most complicated of ARIA Widget types to make accessible, since it involves many different types of user interaction.
Expected behaviors: The entire grid should have only one tab stop, one cell should be focusable at a time, the arrow keys should move focus between cells, Home and End should move focus to the beginning or end of a row, PageUp and PageDown should open the previous or next page of the grid, Alt+PageUp and Alt+PageDown should move focus to the first or last page in the grid, Space and Enter should activate the current cell or row, and textual equivalents should indicate the role and state of each interactive control type for screen reader users.
The Data Grid Module automates these processes by adding all related event handlers and managing all related rendering procedures.
<div id="gridContainerId" ></div>
The following attributes are handled automatically by the Data Grid Module:
var grid = new $A.DataGrid( ContainerNodeOrID );
The first parameter specifies the container element where the data grid will be rendered, and may be a DOM node or an ID string.
// Set the registered columns including unique IDs and label text
// The order of items in the array will dictate the default column ordering when rendered
grid.mapColumnNames([
{
// ID that is associated with all cells in the column
id: 'col1id',
// The text that will be rendered as the column header
lbl: 'User Name',
// Set an optional class to be added to all cells within the column
colClass: 'col1'
},
{
id: 'col2id',
lbl: 'Email Address',
colClass: 'col2'
},
{
id: 'col3id',
lbl: 'Publish Record',
colClass: 'col3'
}
]);
// Programmatically change the order of rendered columns
// This method rearanges the array order of the objects passed to grid.mapColumnNames(ObjArray)
// Which is used to determine rendering order
// This must be followed by grid.open() to rerender the grid after a change is made
// E.G Change the third column to the first column
grid.changeColumnOrder(2, 0);
// Enable row headers and specify the column ID to be used for this purpose
// This must be followed by grid.open() to rerender the grid after a change is made
grid.enableRowHeaders(true, 'col1id');
// Or disable
grid.enableRowHeaders(false);
// Set a maximum number of rows to render before pagination is applied
// If set to 0, all records will render and no pagination will occur
// This must be followed by grid.open() to rerender the grid after a change is made
grid.setRowMax(25);
// Enable or disable editability for grid cells
// This will render an edit field for strings or handle toggle events for buttons.
// This must be followed by grid.open() to rerender the grid after a change is made
grid.editable(true);
// Or to disable
grid.editable(false);
// Add rows to a grid instance
grid.add(rowObject_or_rowObjectArray);
// Each row must adhere to the following object literal format:
{
id: 'uniqueRowId',
cells: {
'col1id': {
// Set the cell type, may be either 'text' or 'toggle'
// Defaults to 'text' if omitted
type: 'text',
// Set an optional readonly flag to disable editability if the grid is editable
// Defaults to false if omitted
readonly: true,
// Set the initial value of the cell
value: 'My User Name'
},
'col2id': {
value: 'email_address@whatever.com'
},
'col3id': {
type: 'toggle',
readonly: false,
value: true,
// For toggles, set the name property to specify a visual textual label
name: 'Published',
// For toggles, specify an optional class to be added when the toggle is set to true
// This will override the general toggle class specified within grid.setStaticClasses
toggleClass: 'toggle-button-pressed'
}
}
}
// Set a value changed listener for handling serverside posting when cell values change
grid.setChangeListener(function(originalCellObject, newValue, rowObject, gridInstance){
// rowObject reflects the same object passed to grid.add
// so that rowObject.id reflects the original unique row ID
// originalCellObject reflects the cell object instance passed within 'cells' when passed to grid.add
// and cellObject.id reflects the column ID, so that rowObject.id and cellObject.id can be used as X Y coordinates to identify the correct cell in the grid.
// Compare originalCellObject.value with newValue to perform input validation or other processes.
// To prevent rendering the changed input or new toggle state, simply return false
});
// Enable or disable double click or single click mouse interaction for selectable rows and editable cells
// This must be followed by grid.open() to rerender the grid after a change is made
// When set to false, a single mouse click will toggle selectability or trigger an edit action
grid.useDblClick(false);
// Enable or disable row selectability
// This must be followed by grid.open() to rerender the grid after a change is made
// When set to true, editability will automatically be set to false to prevent functionality and keyboard accessibility conflicts
grid.setSelect({
enable: true,
// Set a class to be added to the TR node every time a row is selected
toggleClass: 'selected',
// Set single or multiSelect
multiSelect: false,
// Use ARIA for selection or cross-platform offscreen text instead
// Important: The use of aria-selected for row selection is not well supported by screen readers at this time
ariaSelect: false,
// Choose whether rendering another page will automatically unselect previously selected rows
// Set to false to unselect rows automatically, or true to keep selection active
preserve: false,
// Set a callback to execute every time a row is toggled
callback: function(rowObject, state, prevSelectedRowsArray, gridInstance){
// rowObject is the activated row object.
// rowObject.rowNode is the TR DOM node for the toggled row.
// 'state' reflects the proposed state change, which is the opposite of rowObject.selected.
// prevSelectedRowsArray is an array of all previously selected rowObjects, not counting the current rowObject.
// To cancel the toggle action, return false
}
});
// Or pass single properties to set functionality
grid.setSelect({
enable: false
});
// Unselect all previously selected rows
grid.unselectAll();
// Select all rows on the currently rendered page
grid.selectAll();
// Get an array of all currently selected rowObjects
// Each rowObject reflects the same object literal passed in grid.add()
// Get an array of selected rowObjects
var selected = grid.getSelected(),
// Get the row ID for the first selected row
rowId = selected[0].id,
// Or get the TR DOM node of the first selected row
rowNode = selected[0].rowNode;
// Programmatically select one or more rows using an array of row IDs
grid.select(['rowId1', 'rowId2']);
// Enable or disable row deletion
// This must be followed by grid.open() to rerender the grid after a change is made
// When enabled, the Delete key will delete all currently selected rows from the grid and destroy their rowObjects in the cache
// Selectability must be set to true for this functionality to be used
grid.setDelete({
enable: true,
// Set a function to execute prior to deletion
runBefore: function(selectedRowIDs_array){
// Return false to cancel deletion
},
// Set a callback to execute on every row that is deleted
callback: function(rowObject, gridInstance){
// rowObject.id is the table row ID that is being deleted
// alert(rowObject.id);
// return false to cancel deletion from the grid
},
// Set a function to execute after deletion is completed
runAfter: function(deletedRowIDs_array){
// Do something
}
});
// Or to disable
grid.setDelete({
enable: false
});
// Programmatically delete all currently selected rows and destroy their rowObjects in the cache
grid.deleteRows();
// Programmatically delete one or more rows and destroy their rowObjects in the cache using an array of row IDs
grid.deleteRows(['rowId1', 'rowId2']);
// Programmatically delete all rows in the grid instance and destroy their rowObjects in the cache
grid.deleteAllRows();
// set accessible text for screen reader users
grid.setAccessibleText({
// Set offscreen and tooltip text for toggle cells
toggleButtonRole: 'Toggle Button',
toggleButtonState: 'Pressed',
disabledText: 'Disabled',
// Set the page text to be announced to screen reader users during infinite scrolling. E.G "Page 2", "Page 3", etc.
pageRole: 'Page',
// Set the active state and help tooltip text for mouse users
selectState: 'Selected',
editLinkAction: 'Editable',
dblClickTitle: 'Click to activate',
// Set the title text for the edit field
editFieldTitle: 'Press Enter to save, or Escape to cancel.'
});
// Set static classes
grid.setStaticClasses({
// General Table element class for the grid
gridClass: 'data-grid',
// Additional Table element class when the grid is set to Readonly
gridReadOnlyClass: 'data-grid-readonly',
// Additional Table element class when the grid is set to Editable
gridEditableClass: 'data-grid-editable',
// Additional Table element class when the grid is set to Selectable
gridSelectableClass: 'data-grid-selectable',
// General TR element class for the grid
gridRowClass: 'data-grid-row',
// Additional TR element class when a grid row has focus
gridRowFocusedClass: 'data-grid-row-focused',
// General TH and TD element class for the grid
gridCellClass: 'data-grid-cell',
// Additional TD element class when a grid cell is set to Readonly
cellReadOnlyClass: 'data-grid-cell-readonly',
// Additional TD element class when a grid cell has focus
gridCellFocusedClass: 'data-grid-cell-focused',
// General STRONG element class for grid text cells
gridCellLinkClass: 'data-grid-cell-link',
// General STRONG element class for grid toggle cells
gridCellToggleClass: 'data-grid-cell-toggle',
// Additional STRONG element class for grid toggle cells when set to True
gridCellTogglePressedClass: 'data-grid-cell-toggle-pressed',
// General DIV and INPUT element class for grid edit field popups
editFieldClass: 'data-grid-cell-link-edit'
});
// Get the total number of rows in the grid instance
grid.totalRows();
// Pagination: Get the current page number
grid.currentPage();
// Pagination: Get the total number of pages in the grid instance
grid.totalPages();
// Set a page index changed listener to execute every time the current or total number of pages changes within the grid instance
grid.setPageIndexChangeListener(function(currentPage, totalPages, gridInstance){
// Do something
});
// Open a specific page without rerendering the parent grid
grid.openPage(number);
// Open the first page in the grid
grid.firstPage();
// Open the previous page in the grid
grid.prevPage();
// Open the next page in the grid
grid.nextPage();
// Open the last page in the grid
grid.lastPage();
// Execute listener every time a grid object is opened in the DOM
grid.setOpenListener(function(container, dc, gridInstance){
// 'dc' is the grid AccDC Object
});
// Execute listener every time a grid object is closed in the DOM
grid.setCloseListener(function(container, dc, gridInstance){
// 'dc' is the grid AccDC Object
});
// Execute listener every time a grid TR object is rendered in the DOM
grid.setAddListener(function(rowObject, dc, gridInstance){
// rowObject.id is the unique row ID as passed in grid.add()
// rowObject.rowNode is the rendered TR DOM node
// 'dc' is the grid AccDC Object
});
// Execute listener every time a grid TR object is removed from the DOM
grid.setRemoveListener(function(rowObject, dc, gridInstance){
// rowObject.id is the unique row ID as passed in grid.add()
// rowObject.rowNode is the rendered TR DOM node
// 'dc' is the grid AccDC Object
});
// Execute listener every time a grid TD node receives focus
grid.setMoveListener(function(newCell, oldCell, dc, gridInstance){
// 'newCell' is the TD DOM node that has been given focus
// 'oldCell' is the TD DOM node that used to have focus
// 'dc' is the grid AccDC Object
});
// Assign a character maxLength value for the edit text popup
grid.setEditMaxLength(255);
// Set a positioning override for the placement of the edit text popup
// Must return an object literal that contains the following properties: top, left, width, height
grid.setEditOffset(function(cellObject){
// cellObject.cellNode is the DOM node for the TD element that has focus
// cellObject.cellNodeA is the DOM node for the STRONG element contained within the TD element that has focus
var o = $A.xOffset(cellObject.cellNodeA); // Get top and left properties
o.height = $A.xHeight(cellObject.cellNodeA); // Add height
o.width = $A.xWidth(cellObject.cellNodeA); // Add width
return o;
});
// Set an edit field load listener to execute every time the string edit field is opened for a cell
grid.setEditLoadListener(function(editFieldNode, cellObject){
// editFieldNode is the rendered edit Input element
// cellObject is the cellObject that was triggered, providing access to all data associated with that cell
// E.G
// cellObject.cellNode is the actionable TD node that was activated
// cellObject.value is the original value of the cell
// cellObject.id is the column id for that cell
// cellObject.rowObject.id is the unique row ID for that row
// cellObject.rowObject.rowNode is the TR node for that row
});
// Set the value of a specific cell in the grid using its unique row ID and column ID as X Y coordinates
// Row ID refers to the same value stored within rowObject.id, and col ID refers to the same value stored within cellObject.id
grid.setValue('rowID', 'colID', value);
// Get the value of a specific cell in the grid using its unique row ID and column ID as X Y coordinates
// Row ID refers to the same value stored within rowObject.id, and col ID refers to the same value stored within cellObject.id
grid.getValue('rowID', 'colID');
// Programmatically store data within a specific cell in the grid using its unique row ID and column ID as X Y coordinates
// Row ID refers to the same value stored within rowObject.id, and col ID refers to the same value stored within cellObject.id
// When set, the data is alternatively available within the cellObject via cellObject.data['keyname']
grid.setData('rowID', 'colID', 'keyname', data);
// Programmatically retrieve data within a specific cell in the grid using its unique row ID and column ID as X Y coordinates
// Row ID refers to the same value stored within rowObject.id, and col ID refers to the same value stored within cellObject.id
grid.getData('rowID', 'colID', 'keyname');
// Open a grid instance and render a page within the DOM
// If no page number is passed as the first parameter, then 1 is inferred by default
grid.open();
// Or to open a specific page
grid.open(number);
// Close a grid instance and remove it from the DOM
// This will not delete any of the cached rowObjects that were added via grid.add()
grid.close();
// Programmatically set focus to the grid
// This always references the TD node that is currently active
grid.focus();
// Access the grid AccDC Object instance for optional modification
var dc = getAccDCObject();
// Access the container DOM node
var myContainer = grid.container;
The sample data grids in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
You can change the styling however you wish to fit the layout of any UI, and the data grids will still be accessible to both screen reader and keyboard only users regardless.
Simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled data grid will be accessible.
Notes about keyboard interactivity
A focusable ARIA Grid is a complicated concept, and there are only a certain number of keyboard commands available that don't directly conflict with the screen reader or browser. The following keyboard commands should not be used for this reason:
Notes about mouse interactivity
When activating a selectable row or editable cell using the mouse, double click must be used. If a single click is used to invoke this functionality, it will conflict with screen reader behavior. For example, when browsing the page using JAWS in Virtual Cursor mode, it is necessary to press Enter on the desired grid cell to enter Applications Mode. When JAWS does this, it automatically activates the click event, which automatically invokes selection or editing for that cell. When double click is used instead, this conflict does not occur. Single tapping of a selectable or editable cell using a touch screen device however, works using one click.
The ARIA Date Picker is a complex control type with a simple implementation.
Expected behaviors: The associated INPUT field should not include readonly, an external triggering element should activate the date picker, the arrow keys should move between calendar cells and the calendar should scroll automatically between months, PageUp/PageDown should switch between months, Alt+PageUp/PageDown should switch between years, Enter should activate the selected date, and pressing Escape or Tab should close the calendar and return focus to the triggering element.
The Calendar Module automates these processes by adding all related event handlers and managing all related rendering procedures.
<input type="text" id="dateInputId" title="Label text if no Label element is associated" /> <a href="#" id="datePickerId"> Calendar Icon Name </a>
Form field HTML markup requirements:
$A.setCalendar( 'UniqueCalendarId' , $A.getEl('datePickerId'), $A.getEl('dateInputId'), EnableComments<true/false> ,
clickHandlerCallbackFunction(ev, dc, targetElementObj){
// Configure date string and save it within targetElementObj
targetElementObj.value = dc.range.wDays[dc.range.current.wDay].lng + ' ' + dc.range[dc.range.current.month].name + ' '
+ dc.range.current.mDay + ', ' + dc.range.current.year;
// Then close the calendar
dc.close();
}, {
// Configuration key / value map overrides
});
The first parameter must be unique for every calendar declaration, since this is registered as the ID of the Calendar AccDC Object when instantiated.
The second parameter is the DOM object for the triggering element.
The third parameter is the DOM object for the target INPUT element.
The fourth parameter is a Boolean that determines whether comments will be displayed when associated with dates.
False is set by default if no value is specified.
The fifth parameter specifies a callback function where the returned date string can be customized.
The sixth parameter is a key / value map where overrides can be declared to further customize functionality.
Example:
{
// Configure optional overrides
// If not included, all of the below values are set by default
// Set role name text for screen reader users
role: 'Calendar',
// Set tooltip text
tooltipTxt: 'Press Escape to cancel',
disabledTxt: 'Disabled',
commentedTxt: 'Has Comment',
prevTxt: 'Previous',
nextTxt: 'Next',
monthTxt: 'Month',
yearTxt: 'Year',
// Set month names
months:
[
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
],
// Set short and long weekday names
days:
[
{
s: 'S',
l: 'Sunday'
},
{
s: 'M',
l: 'Monday'
},
{
s: 'T',
l: 'Tuesday'
},
{
s: 'W',
l: 'Wednesday'
},
{
s: 'T',
l: 'Thursday'
},
{
s: 'F',
l: 'Friday'
},
{
s: 'S',
l: 'Saturday'
}
],
// Set positive or negative offset for differing column arrangements, or 0 for none
wdOffset: 0,
// Set CSS positioning calculation for the calendar
autoPosition: 9,
// Customize with positive or negative offsets
offsetTop: 0,
offsetLeft: 0,
// Set class for the calendar container
className: 'calendar',
// Choose a different insertion point in the DOM; must be a DOM node; defaults to the triggering element if not specified.
targetObj: null,
// Choose a different focus element in the DOM for CSS autoPositioning; may be a DOM node or CSS Selector; defaults to the triggering element if not specified.
posAnchor: '',
// Configure the Comments tooltip pane
comments:
{
role: 'Comment',
autoPosition: 1,
offsetTop: 0,
offsetLeft: 0,
className: 'commentTooltip'
},
// Configure the editor form pane
editor:
{
// Choose to show the form, defaults to false
show: false,
// Set the section name, and the Edit button text
role: 'Edit',
autoPosition: 6,
offsetTop: 0,
offsetLeft: 0,
className: 'commentAdd',
// Set the Save button text
action1: 'Save'
},
// Manually configure the calendar using AJAX or a customization script
ajax: function(dc, save){
// 'save' is true when closing the Editor, false otherwise for fetching content when the calendar is opened.
// If save is false, execute load script
if (!save){
// Optionally load custom values into the dc.range associative array.
// And optionally prevent this script from running again
// dc.stopAjax = true;
// Then open the calendar after processing is finished
dc.open();
}
else{
// Otherwise do something with the newly saved values within the dc.range associative array.
}
}
}
Every Date Picker is registered as an AccDC Object, the ID of which matches the ID string declared in the first parameter of the invocation statement.
This also makes it possible to control the calendar programmatically using JavaScript, like so:
var dc = $A.reg['UniqueCalendarId']; // Which you can then open dc.open(); // Or close dc.close(); // All other AccDC API properties and methods can be applied here as well.
Regarding the triggering element, you should always use an active element for this purpose to ensure accessibility for both screen reader and keyboard only users.
Within the Coding Arena samples, these are standard image links (A tags with an Href attribute and an embedded IMG tag with an informative Alt attribute). However, you can use whatever type of triggering element you wish, a standard link, button, or image link, with any type of styling. There must be an active element as a triggering element though, to ensure accessibility.
The sample calendars in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
You can change the styling however you wish to fit the layout of any UI, and the calendars will still be accessible to both screen reader and keyboard only users regardless.
Simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled calendar will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The calendars within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accCalendar", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes:
The date string format is configurable within the callback function, or within the "accdc_bootstrap.js" module if bootstrapped.
The variables to reference are as follows:
var weekDay = dc.range.wDays[dc.range.current.wDay].lng; // 'Friday' var monthName = dc.range[dc.range.current.month].name; // 'November' // or (dc.range.current.month+1) = numerical month string var monthDay = dc.range.current.mDay; // '30' var year = dc.range.current.year; // '2012'
The returned values will reflect the date selected.
The ARIA Listbox is a simple concept, turned into a powerful component.
Expected behaviors: ARIA Listboxes should only receive one tab stop, the Up/Down/Home/End keys should move focus appropriately, and every listbox and listbox option should be explicitly labeled.
The Listbox Module automates these processes by adding all related event handlers and managing all related rendering procedures.
<ul role="listbox" id="uniqueId1" > <li> <a href="#" role="option" id="uniqueId2" > <span class="lbl"> Option One Name </span> </a> </li> <li> <a href="#" role="option" id="uniqueId3" > <span class="lbl"> Option Two Name </span> </a> </li> <li> <a href="#" role="option" id="uniqueId4" > <span class="lbl"> Option Three Name </span> </a> </li> </ul>
Required attributes:
The following attributes are handled automatically by the Listbox Module:
var myListbox = new $A.Listbox( $A.getEl('uniqueId1'), {
// Configuration key / value mappings
});
The first parameter is the DOM node for the listbox container element that includes role="listbox".
The second parameter is the object literal used to configure listbox functionality using key / value map overrides.
Example:
{
// Set the initial list option node to be selected
defaultIndex: 0,
// Set a label for screen reader users
label: 'Unique field label text',
// Choose whether the Listbox is single or multiselect (multiselect is ignored when isSortable=true)
isMultiselect: false,
// Choose whether the Listbox is sortable
isSortable: false,
// Choose whether the Delete key can be used to remove list option nodes
allowDelete: false,
// Help messages that are announced to screen reader users when isSortable=true
grabInstruct: 'Press Space to grab',
dropInstruct: 'Press Space to drop',
grabMsg: 'Grabbed',
dropMsg: 'Moved',
cancelDrop: 'Grab canceled',
// Do stuff whenever the selection changes
callback: function(optionNode, optionsArray){
// this.val() returns the current value of the Listbox control, a string if single-select or an array of strings if multiselect
}
}
Since the Listbox control is an instantiated object, all of the following public properties and methods are available:
myListbox.container; // The Listbox DOM node for the element with role="listbox"
myListbox.options; // The array of list option DOM nodes that contain role="option"
myListbox.index; // The array index number for the currently selected list option element (relative to myListbox.options)
myListbox.grabbed; // The ID string value of the currently grabbed list option DOM node (when isSortable=true)
myListbox.val(); // Returns the current value of the Listbox control: An ID string when the listbox is single-select; an array of ID strings when the Listbox is a multiselect.
myListbox.val(indexValue); // Sets the current Listbox selection to the specified array index value (relative to myListbox.options)
myListbox.val('IdString'); // Sets the current Listbox selection to the specified list option DOM node that matches this ID (contained within myListbox.options)
myListbox.val(['IdString1', 'IdString2']); // Sets the current Listbox selection to all of the list option DOM nodes that match the ID strings in the array (when isMultiselect=true and contained within myListbox.options)
myListbox.val([]); // Clears all previously 'grabbed' or 'checked' list options if either isSortable or isMultiselect is set to True.
myListbox.rem(indexValue); // Removes the list option DOM node from myListbox.options at the specified array index value, and returns the removed A tag DOM node.
myListbox.rem('IdString'); // Removes the list option DOM node from myListbox.options by matching the ID, and returns the removed A tag DOM node.
myListbox.rem(['IdString1', 'IdString2']); // Removes the array of list option DOM nodes from myListbox.options by matching the IDs, and returns the removed A tag DOM nodes in an array.
myListbox.add(A-TagDOM-Node); // Adds a new list option to the Listbox. (Must be an A tag DOM node that includes a unique ID attribute value, an Href attribute for keyboard accessibility, and innerText to set the screen reader accessible label text)
myListbox.add([A-TagDOM-Node1, A-TagDOM-Node2]); // Adds an array of new list options to the Listbox. (Must include A tag DOM nodes that include a unique ID attribute value, an Href attribute for keyboard accessibility, and innerText to set the screen reader accessible label text)
myListbox.activate.apply(listOptionDOM-Node); // Programmatically activate the 'grab' or 'check' functionality for a specific list option DOM node (within myListbox.options when either isSortable or isMultiselect is set to True). The single parameter for this statement must consist of the A tag DOM node for the list option that you wish to activate. This simply performs a toggle action on the specified option, and does not specify a particular state.
The sample listboxes in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the listbox. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled listbox will be accessible.
All list option elements must be marked up as links (A tags with an Href attribute) to ensure backwards compatibility and graceful degradation. These are the only elements that will receive keyboard focus.
All list option elements, as well as the listbox container, must include unique ID attribute values.
In the case of the list option elements, the ID is used as the value of the Listbox control, so when an item is activated, the value of the Listbox will be returned as the ID value for the active A tag. For standard Listboxes, this is the ID of the currently selected list option as a string. E.G "uniqueId2" For Multiselect Listboxes, This is an array of the ID strings of the currently checked list options. E.G ["uniqueId2", "uniqueId4"]
An innerText label for each A tag must be included to ensure accessibility for screen reader users, though you may position this text offscreen to hide it visually if desired.
Alternatively, you may also include IMG tags within the A tags to form image links. When an IMG tag includes an informative Alt attribute, this text is also included as part of the list option label for screen reader users.
If a background image is used instead however, then there must be an innerText label, even if positioned offscreen, to ensure accessibility for screen reader users.
All list option label text must be unique, to prevent confusion for screen reader users.
An ARIA Menu is a simple control type that can easily be made accessible.
Expected behaviors: A keyboard accessible mechanism opens the menu, the arrow keys are used to browse available menu items or open and close submenus, pressing Tab will close all open menus, and pressing Escape will close the currently open menu.
ARIA menus can be implemented in two ways, horizontally or vertically.
This has nothing to do with what they look like, since the CSS styling can be set to whatever you like, but rather, refers to the keyboard interaction model for each menu.
A vertical menu is navigated using the Up and Down arrow keys to scroll through menu items, and Left and Right are used to close or open submenus.
A horizontal menu is navigated using the Left and Right arrow keys to scroll through menu items, and Up and Down are used to close or open submenus.
You can optionally set different interaction models for specific menus or submenus depending on how the menu is visually presented, so that the behavior properly fits the UI design.
Additionally, a menu may be triggered using either the left or right click, with accompanying behaviors for each.
A left click menu often uses a link or button as the triggering element, and also supports the Down arrow, Enter, and Space keys to invoke the menu from the keyboard.
For more complex controls, such as interactive ARIA Widgets that include their own functionality attached to the arrow keys and the left click handler, the right click menu may be used, which also supports the Shift+F10 and Application keystrokes for keyboard support.
The right click menu may also be used on the Body element to present a customized page wide context menu that has no dedicated triggering element.
The Menu Module automates these processes by adding all related event handlers and managing all related rendering procedures.
Basic menu structure with no submenus:
<ol class="menu" id="uniqueId1"> <li> <a href="#" class="link" id="uniqueId2"> Menu Item One Name </a> </li> <li> <a href="#" class="link" id="uniqueId3"> Menu Item Two Name </a> </li> <li> <a href="#" class="link" id="uniqueId4"> Menu Item Three Name </a> </li> </ol>
Basic menu structure with nested submenus:
<ol class="menu" id="uniqueId1"> <li> <a href="#" class="submenu" id="-uniqueId2"> Subfolder Menu Item One Name (Level 1) </a> <ol class="menu" id="uniqueId1-uniqueId2"> <li> <a href="#" class="submenu" id="-uniqueId2-1"> Subfolder Submenu Item One Name (Level 2) </a> <ol class="menu" id="uniqueId1-uniqueId2-uniqueId2-1"> <li> <a href="#" class="link" id="uniqueId2-1-1"> Submenu Item One Name (Level 3) </a> </li> </ol> </li> <li> <a href="#" class="link" id="uniqueId2-2"> Submenu Item Two Name (Level 2) </a> </li> </ol> </li> <li> <a href="#" class="link" id="uniqueId3"> Menu Item Two Name (Level 1) </a> </li> </ol>
The HTML menu syntax is flexible, and may consist of UL tags, OL tags, DIV tags, or any other combination, as long as the container element includes a unique ID, as well as each menu item tag.
For simplicity, these have been marked up as list elements, which is generally preferable since it includes native screen reader support for nested lists. Also, the use of standard A tags with an Href attribute ensures keyboard accessibility across all Assistive Technologies for graceful degradation.
You may also use additional HTML markup within the menu item links for formatting purposes (such as SPAN tags), as long as you don't add additional active elements such as clickable images. The only actionable element should be the menu item link, and nothing else.
Submenus are mapped by combining the ID attribute value of the container element, with the ID attribute value of the submenu link. The two combined point to the full ID attribute value of the associated submenu container element.
For example, notice the ID value on the top level menu OL tag above is id="uniqueId1", and the ID of the first Subfolder A tag within that structure is id="-uniqueId2".
When you combine the two ("uniqueId1-uniqueId2"), notice that this directly points to the submenu OL tag as its ID attribute value.
You can experiment with this in the Coding Arena "Shell" folders, where the same code is used.
Important: Don't add any ARIA attributes to the markup, and don't add tabindex attributes. All of these are handled automatically when the menus are rendered.
If the menu constructs are contained within the same page, they must be contained within a container element that has an ID attribute. This is used by the setup function to confine the parsing query to this node only.
Example:
<div id="hiddenDivId" class="hidden"> <ol class="menu" id="uniqueId1"> ... </ol> </div>
The following attributes are handled automatically by the Menu Module:
HTML5 attributes that can optionally be added to the menu list container markup:
Value Definitions:
Example:
<ol class="menu" id="uniqueId1-uniqueId2-uniqueId2-1" data-horizontal="true" data-offsetleft="10" data-offsettop="-20" data-autoposition="3"> ... </ol>
$A.setMenu( 'CSS-SelectorForTriggeringElement' , 'LocalePathOrContainerID' , 'TopLevelMenuID' ,
callbackFunction(ev, dc){
// Do something every time a menu item link node is clicked
} , areMenusInTheSameDoc? , contextDOM-Node , {
// Configure key / value mapping overrides
});
Parameter 1: The triggering element CSS Selector :
This points to the triggering element link or button that you want to use as the menu triggering element. For instance, the CSS Selector "a.button" points to the A tag with class="button" for this purpose.
Multiple triggering elements that open the same menu may be specified using one CSS Selector.
Parameter 2: The Locale Path or Container ID :
When menus are contained within an external HTML file, this string value is the relative file path, such as "files/menus.html".
When menus are contained within the same page, this string value is the ID attribute of the container element where all of the menu tags are located, such as "hiddenDivId".
Parameter 3: Top Level Menu ID:
This string is the top level menu ID attribute value, such as "uniqueId1", which is used to specify which menu will be opened first when the triggering element is activated.
Parameter 4: The Callback Function:
This is where you can set specific functionality to occur whenever a menu item link is activated, whether this is to navigate to another page, or to perform another client side action.
When declared, two arguments are passed to the function, first is the event object, and the second is the AccDC Object for the currently open menu object.
Using 'this' within the function will reference the DOM node for the activated element, which is useful if mapping the ID attribute to a particular action.
dc.top.triggerObj (where dc is the AccDC Object) provides the DOM node for the original triggering element that first opened the menu.
Parameter 5: Are Menus within the Same Doc:
A Boolean (true or false), that specifies whether the script should process the Locale parameter as an internal or external resource locator.
If menu markup is contained within an external HTML file, set this to false, otherwise set to true.
Parameter 6: The Context DOM Node:
This is the DOM node that will be used to confine the parsing query.
Typically this is set to document, since all of the IDs are relative to this location.
However, this parameter gives you the ability to reference iFrame documents instead if desired.
Parameter 7: The Config Object:
This is a key / value mapping of overrides that can be used to customize the element types of menu container and menu item elements, the class names for each, the default keyboard interaction model, the default auto positioning if desired, plus additional AccDC API overrides if desired.
Example:
{
// Enable right click functionality
// Automatically configures keyboard support using Shift+F10 and the Applications key
// When set to false, the Enter, Space, and Down arrow keys are supported in addition to onclick
rightClick: true, // Default: false
// Set the accessible help description that will be announced for screen reader users
// Only applicable when rightClick is set to true
// Will automatically clear on touch screen devices to prevent confusion
rightClickText: 'Press Shift+F10 or the Applications key to open the popup menu',
// Set the main container class, (which will surround the menu as a Div tag when rendered)
containerClass: 'menu',
// Specify the menu tag name in the markup
menuTag: 'ol',
// Specify the menu class name on the above tag in the markup
menuClass: 'menu',
// Specify the active element that will be used as each menu node
// Important, if nesting A tags within LIs, only the A tag should be used for this purpose
// Active elements should never be nested.
// The following tag will receive keyboard focus within the menu structure when using the arrow keys to navigate
// Event bindings are also tied to this tag
itemTag: 'a',
// Specify the class name that indicates when a menu item opens a submenu
folderClass: 'submenu',
// Specify the class name that indicates when a menu item is to be triggered directly
// This should not be the same as the folderClass declaration
linkClass: 'link',
// Specify if the menu is a flyout menu
// If true, the Left and Right arrow keys will scroll the open menu
// If false, the Up and Down arrow keys will scroll the open menu instead
horizontal: false,
// Set a default autoPosition value between 0 (disabled) and 12
autoPosition: 0,
// Set custom offset values to adjust the positioning calculation
// May return a positive or negative number
offsetLeft: function(dc){
return 0;
},
offsetTop: function(dc){
return 0;
},
overrides: {
// Additional AccDC API properties and methods can be applied here if desired.
}
}
Every menu instance is registered as an AccDC Object, the ID of which matches the ID attribute value on the menu container element.
This means that you can programmatically control each menu using JavaScript if desired, like so:
// Get a reference to the top level Menu AccDC Object for the menu container with id="uniqueId" var dc = $A.reg['uniqueId']; // Now invoke the object dc.open(); // Or close it dc.close(); // All other AccDC API properties and methods can be applied here as well.
Additionally, when a menu is attached to a triggering element, the custom handler 'popupmenu' is attached to that element.
To support both standard and touch device usage as part of responsive design, a specially displayed icon (typically referred to as a Hamburger icon) is often displayed conditionally on touch screen devices to allow for context menus to be actionable.
Reference: http://gizmodo.com/who-designed-the-iconic-hamburger-icon-1555438787
Such an icon can be programmatically configured to open the popup menu attached to the triggering element by manually triggering the 'popupmenu' event on that element.
// Detect if running on a touch device
if ('ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0){
// Unhide the hamburger icon and attach an onclick handler
$A.bind($A.remClass(hamburgerIconElement, 'hidden'), 'click', function(ev){
// Trigger the menu attached to the original triggering element
$A.trigger(originalTriggeringElement, 'popupmenu');
ev.stopPropagation(); // Important to prevent bubbling and auto closing
ev.preventDefault();
});
}
Similarly, a currently open menu can be programmatically closed by triggering the 'closepopupmenu' event on the triggering element.
// Close the menu attached to the original triggering element $A.trigger(originalTriggeringElement, 'closepopupmenu');
When aria-disabled="true" is programmatically set on any menu item node after rendering, it will automatically be disabled within the menu, so that disabled submenus will not open when clicked or arrowed to, and custom handling for non-submenu links can then be processed individually within the click callback.
When a custom menu is applied to the Body element, no triggering element is required.
All other usages for custom popup menus require the use of a keyboard focusable active element that includes a valid active element role, which may consist of any native active element such as a standard link or form field, or a keyboard accessible interactive ARIA Widget type.
Valid interactive ARIA Widget roles include:
Reference: http://www.w3.org/TR/wai-aria/roles
The sample menus in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the menu. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled menu will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The menus within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accMenu", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes for the triggering element:
The lists can be set to any tag, such as OL, UL, etc, as long as this is specified in the menuTag property within the JavaScript declaration statement or within the data-menutag attribute on the triggering element if Bootstrapped.
The same is true for the menu item nodes, which is specified using the menuItemTag property in the JavaScript declaration statement, or within the data-menuitemtag attribute on the triggering element if Bootstrapped.
Menus and submenus may be nested or broken out into separate lists within the markup if desired, as long as they are all contained within the same top level container element specified by ID within the JavaScript invocation statement, or within the data-internal attribute on the triggering element if Bootstrapped.
All menu container elements and menu item nodes must include unique ID attributes.
Submenus are mapped by combining the ID attribute of the top level menu container ID and the submenu pointer link ID, which, when combined, points to the ID of the referenced submenu container.
All menu item nodes must include innerText to ensure accessibility for screen reader users.
Don't include any ARIA attributes within the menu markup, since this is handled automatically by the Menu module.
ARIA Radio buttons provide a means for rendering standard links as a radio button group.
Expected behaviors: Only one radio button should receive focus in the tab order, regardless whether one or no radio button in the group is selected. If a radio button is selected, only the currently selected radio button should appear in the tab order. The arrow keys should move focus to the next or previous radio button in the group, and the act of moving to that radio button should automatically select it.
The Radio Button Module automates these processes by adding all related event handlers and managing keyboard focus appropriately.
<ul id="radiogroupId" role="radiogroup"> <li> <a href="#" role="radio" class="accRadio" id="rOpt1" aria-labelledby="rOpt1Lbl"> <span id="rOpt1Lbl"> Radio One Label Text </span> </a> </li> <li> <a href="#" role="radio" class="accRadio" id="rOpt2" aria-labelledby="rOpt2Lbl"> <span id="rOpt2Lbl"> Radio Two Label Text </span> </a> </li> <li> <a href="#" role="radio" class="accRadio" id="rOpt3" aria-labelledby="rOpt3Lbl"> <span id="rOpt3Lbl"> Radio Three Label Text </span> </a> </li> </ul>
Markup requirements:
The following attributes are handled automatically by the Radio Button Module:
var myRadioGroup = new $A.RadioGroup( 'radiogroupId' , 'CSS Selector for All Radio Elements' , DefaultIndexValue , 'Optional Legend Text' ,
callbackFunction(selectedRadioNode, radiosArray){
// Do something whenever a radio is selected
// this.value is the ID value of the newly selected radio element
} );
Parameter 1: The ID attribute of the radio group container. (This is the element with role="radiogroup")
Parameter 2: The CSS Selector that identifies all elements with role="option" (all of which must be contained within the container specified in parameter 1)
Parameter 3: The array index of the radio button that you want to be selected by default when instantiated.
(Simply pass -1 to specify that no radio button should be selected by default)
Parameter 4: The shared legend text that will be announced to screen reader users whenever a radio button group receives initial focus.
The legend text will be announced in addition to the textual label for the radio button.
To use a visually displayed legend instead (as demonstrated within the Coding Arena samples), use aria-labelledby on the element with role="radiogroup", and pass "" to this parameter to skip it.
Parameter 5: The callback function that will be executed whenever a new radio button is activated.
When a radio button grouping is instantiated as a new Radio Group Control, all of the following public properties and methods are available:
('myRadiogroup' refers to the variable instance name)
myRadiogroup.radios; // The array of all radio option DOM nodes
myRadiogroup.index; // The array index of the currently selected radio option
myRadiogroup.value; // The string ID attribute value of the currently selected radio option
myRadiogroup.set('radioId'); // Sets the radio option with id="radioId"
myRadiogroup.set(arrayIndex); // Sets the radio option at the specified array index (relative to myRadiogroup.radios)
The sample radios in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the radio group. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled radio group will be accessible.
ARIA Sliders are used to present adjustable values for users, and can easily be made accessible.
Expected behaviors: The slider should have only one tab stop in the tab order, the arrow keys should move the slider in single value increments, PageUp/PageDown should move the slider in 10% increments, Home/End should move the slider to the beginning or end, and the slider should be draggable using the mouse as usual.
The Slider Module automates these processes by adding all related event handlers and managing keyboard focus appropriately.
<div class="slider"> <div class="min" aria-hidden="true"> <span>0%</span> </div> <div class="slideWrapper"> <div class="slide clearfix"> <div class="nub" id="handleId"><!-- This is the slider thumb icon --></div> </div> </div> <div class="max" aria-hidden="true"> <span>100%</span> </div> </div>
Important: The first parentNode container of the draggable slide element must be relatively positioned to set this as the offsetParent. In the above markup, this is the Div tag with class="slide clearfix".
Also, notice that aria-hidden="true" is used on the Min and Max container tags. Since these values will be provided to screen reader users as part of the ARIA Slider Control, having them announced during navigation would only repeat the same information twice, which is unnecessary. So aria-hidden is used to remove them from the Virtual Buffer for screen reader users.
The next step is to use CSS to set the width and height of the slider, which you can see examples of in the Coding Arena samples. This is important, because when the Slider Control is instantiated, it will use these offsets to configure the positioning calculations and map them to related keyboard commands.
The following attributes are handled automatically by the Slider Module:
$A.setSlider('handleId', {
// Configure key / value mappings
});
The first parameter is the ID of the element that will be made draggable, which will then be morphed into an AccDC Object. E.G "handleId" The markup structure will slightly change at this point, since an extra DIV will then surround the element with id="handleId".
The second parameter is where all of the slider configuration is set.
Example:
{
// Set the role text that is conveyed to screen reader users
role: 'Slider',
// Set a minimum value
min: 0,
// Set a maximum value
max: 100,
// Set the start value
now: 50,
// Is a vertical slider?
vertical: false,
// Set the hidden link text for graceful degradation
// This should reflect the purpose of the slider
degradeLbl: 'Manually choose a percentage',
// Return the string that will act as the ARIA Slider label for screen reader users
// This should reflect the purpose of the slider
ariaLabel: function(dc){
return 'Choose a percentage between 0 and 100';
},
// Return the string that will act as the textual notification for screen reader users
// This is automatically announced every time the slider is moved
valueText: function(dc, val){
return val + '%';
},
// Set the action to occur whenever the value changes
onDrag: function(ev, dd, dc, val){
// ev is the standard event object
// dd is the custom drag event object
// dc is the AccDC Object for the Slider
// val is the current value of the slider
},
// Set the class name for the surrounding Div, which automatically surrounds the drag handle element
className: 'handleWrapper'
}
After a Slider Control is instantiated, it can be controlled programmatically using its ID, which matches the ID attribute value of the drag handle (passed as the first parameter in the invocation statement).
Example:
// Get a reference to the Slider AccDC Object using its ID, which matches the handle elements ID attribute var dc = $A.reg['handleId']; // Get the current slider value var currentVal = dc.config.now; // Assign a new slider value dc.config.now = currentVal + 10; // Apply the change dc.set.apply(dc);
The sample sliders in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled sliders will be accessible.
Simply use CSS to set the size of the slider, and the height and width of the container element, and then the slider will configure itself using these offsets.
Since repetitive labels are used, and the textual slider icon has no value for screen reader users, aria-hidden="true" is used to hide them from screen reader users.
Don't include any other ARIA attributes however, the Slider module handles this automatically.
The slide icon can be changed to anything, or an image or CSS background image can be used instead, and the styling can be configured for any layout, and it will still be accessible for screen reader and keyboard only users.
VoiceOver instructions for use on iOS touch screen devices:
When VoiceOver is used on iOS touch screen devices, VoiceOver instructs the user to swipe up and down with one finger to adjust the slider value, which is incorrect. (Last verified on 04/07/2013)
Instead, do the following:
(Credit goes to David Hilbert Poehlman for providing VoiceOver pass-through technique instructions.)
The Toggle Control is a multipurpose control type, that covers checkboxes, toggle buttons, and even simulated links and buttons.
Expected behaviors: The general behavior of a Toggle control is to receive keyboard focus in the tab order regardless of the active select state, to be toggleable or actionable by pressing the Spacebar or by pressing Enter on the control, and to be toggleable or actionable by clicking it as usual.
The Toggle Module automates these processes by adding all related event handlers.
The HTML syntax varies depending on which type of implementation is desired, and each type has specific rules that must be observed in order to ensure the highest level of accessibility for screen reader users.
IMG
For IMG tags, the following attributes are required to ensure accessibility for the widest range of screen readers:
Examples:
<img role="button" aria-label="Toggle Button Label" alt="Toggle Button Label" title="Toggle Button Label" id="uniqueId1" src="icon.png" /> <img role="checkbox" aria-label="Checkbox Label" alt="Checkbox Label" title="Checkbox Label" id="uniqueId2" src="icon.png" />
INPUT
For INPUT tags with type="image", the following attributes are required to ensure accessibility for the widest range of screen readers:
Examples:
<input type="image" role="button" aria-label="Toggle Button Label" alt="Toggle Button Label" title="Toggle Button Label" id="uniqueId3" src="icon.png" /> <input type="image" role="checkbox" aria-label="Checkbox Label" alt="Checkbox Label" title="Checkbox Label" id="uniqueId4" src="icon.png" />
Container Elements
For all other container elements that support innerHTML such as DIVs and SPANs, the following attributes and rules are required to ensure accessibility for the widest range of screen readers:
Examples:
<div role="button" title="Toggle Button Label" id="uniqueId5"> <span class="lbl"> Toggle Button Label </span> </div> <div role="checkbox" title="Checkbox Label" id="uniqueId6"> <span class="lbl"> Checkbox Label </span> </div>
The following attributes are handled automatically by the Toggle Module:
var myToggle = new $A.Toggle('uniqueId', {
// Configure key / value mappings
});
The first parameter is the ID attribute value of the element that will become actionable.
The second parameter is the key / value map that configures specific functionality.
Example:
{
// Disable ARIA
// (only for simulated Checkboxes and Toggle Buttons, leave out otherwise)
noARIA: true,
// Disable toggling
// (only for ARIA Links and Buttons, leave out otherwise)
noToggle: true,
// Set the initial state
// (only for simulated Checkboxes and Toggle Buttons, leave out otherwise)
state: false,
// Declare a callback to run every time the state changes
callback: function(state){
// 'state' is the proposed state change, true or false
// 'this' is the triggering element
// Return true to accept the ARIA state change, or false to prevent
return true;
}
}
After a Toggle control is instantiated, the following public properties and methods are available:
myToggle.state; // Reflects the current select state of the toggle (true or false) myToggle.set(Boolean); // Set the Toggle with the specified state (true or false)
The samples in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled checkbox or button will be accessible.
An ARIA Tree is a complex control type that requires a lot of synchronizing to make accessible.
The reasons why: If the right ARIA attributes are not applied to the correct DOM nodes that receive keyboard focus, and if the parent child ID associations are not properly mapped and maintained, and if tree nodes are not labeled properly using the correct ARIA attributes, and if the tree contains any other active elements that are not part of the ARIA Tree structure, then the ARIA Tree and its contents will not be accessible for screen reader users.
Currently, a large part of this is the result of unequal support by screen reader manufacturers. For example, even though the ARIA specification states that role="document" can be used to embed additional content panels within specific widgets such as this, doing so will result in content panels that are inaccessible using JAWS in both IE and Firefox. (Verified in JAWS 12, 13, and 14)
Nevertheless, the Tree Module automates these processes accessibly by adding all related event handlers and managing all related rendering procedures using an external XML file for configuration.
<div id="myTreeId"></div>
<?xml version="1.0" encoding="UTF-8" ?> <tree> <branch id="uniqueId0-1" name="Branch Link Name for id=uniqueId0-1"> <leaf id="uniqueId0-1-1" name="Leaf Link Name for id=uniqueId0-1-1"></leaf> </branch> <leaf id="uniqueId0-2" name="Leaf Link Name for id=uniqueId0-2"></leaf> </tree>
The above XML markup results in the following HTML structure when rendered:
<div class="TreeView"> <div> <ul role="tree" aria-owns="uniqueId0-1 uniqueId0-2" aria-label="Informative Field Name"> <li> <a class="branch" aria-expanded="true" id="uniqueId0-1" aria-level="1" role="treeitem" aria-posinset="1" tabIndex="0" aria-selected="true" aria-owns="aria1363672754457" aria-setsize="2" href="#" aria-label="Branch Link Name for id=uniqueId0-1"> <SPAN>Branch Link Name for id=uniqueId0-1</SPAN> </a> <div class="TreeView"> <div> <ul id="aria1363672754457" role="group" aria-owns="uniqueId0-1-1"> <li> <a class="leaf" id="uniqueId0-1-1" aria-level="2" role="treeitem" aria-posinset="1" tabIndex="-1" aria-selected="false" aria-setsize="1" href="#" aria-label="Leaf Link Name for id=uniqueId0-1-1"> <SPAN>Leaf Link Name for id=uniqueId0-1-1</SPAN> </a> </li> </ul> </div> </div> </li> <li> <a class="leaf" id="uniqueId0-2" aria-level="1" role="treeitem" aria-posinset="2" tabIndex="-1" aria-selected="false" aria-setsize="2" href="#" aria-label="Leaf Link Name for id=uniqueId0-2"> <SPAN>Leaf Link Name for id=uniqueId0-2</SPAN> </a> </li> </ul> </div> </div>
Required XML attributes:
The following attributes are handled automatically by the ARIA Tree Module:
var treeId = $A.setTree({
// Configuration key / value map
});
The first parameter is used to configure ARIA Tree functionality using a key / value map.
Example:
{
// Set the XML file to parse
path: 'files/tree.xml',
// Set the label that will be announced to screen reader users
title: 'Informative Field Name',
// Specify the container element where the tree nodes will be inserted
container: 'div#myTree',
// Set the class name shared by all tree AccDC Objects when rendered
topClass: 'TreeView',
// Set the container tree node type
treeTag: 'ul',
// Set the divider node type that will be appended to the treeTag node
dividerTag: 'li',
// Set the focusable tree item node type that will be inserted within dividerTag node
treeItemTag: 'a',
// Set the shared class name for all tree items that expand into subfolders
treeClass: 'branch',
// Set the shared class name for all tree items that do not expand into subfolders
treeItemClass: 'leaf',
// Set the class name that is only set on the tree item node that has focus
selectClass: 'selected',
// Set the handler type that will trigger the callback
bind: 'click',
// Declare a callback function
callback: function(ev, dc){
// Get the XML node that matches the ID attribute of the currently triggered element
var xmlNode = $A.query('#' + this.id, dc.top.xmlDocument)[0];
// To learn more about the XML DOM and supported properties and methods,
// and how to access custom attributes on each node, visit
// http://www.w3schools.com/dom/default.asp
},
overrides: {
// Set optional AccDC API overrides for every AccDC Object that is rendered in the tree
}
}
The invocation statement returns the top level ID of the newly instantiated ARIA Tree control, which is now registered as an AccDC Object.
You can use this ID to programmatically change or invoke AccDC API properties and methods within the ARIA Tree structure, and to traverse the parent / child relationship of tree node objects.
Example:
// Get the Tree AccDC Object using the ID stored in the variable treeId var dc = $A.reg[treeId];
Now, you can traverse the expandable branches in the tree using dc.siblings, dc.children, dc.parent, and dc.top, and apply changes, store and retrieve data, or invoke AccDC API commands as desired.
Example:
// Close the Tree AccDC Object and remove it from the DOM. dc.top.close(); // All other AccDC API properties and methods are similarly available.
The sample trees in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the tree. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled tree will be accessible.
A Banner is a simple control type, which can easily be made accessible.
Expected behaviors: Ensure that the content of the banner appears at the top of the page, ensure that the beginning and ending boundaries are conveyed to screen reader users, and make sure the banner can be closed from the keyboard (if applicable).
The Banner Module automates these processes by instantiating banner content as an AccDC Object.
<div id="bannerContainerElementId"> Banner content goes here. </div>
var bannerId = $A.setBanner({
// Configure functionality key / value map
});
The first parameter configures banner functionality using a key / value map.
Example:
{
// Set a unique ID for the Banner AccDC Object
id: 'myBannerId',
// Set the boundary text for screen reader users
role: 'Banner',
// Set the Banner AccDC Object to render literal content
// (Only if pulling content from within the same page, remove otherwise)
mode: 0,
// Set the content to be rendered by pulling it from within the same page
// 'removeChild' is important here, so no duplicate ID conflicts can occur when the object is opened and closed
// (Only if pulling content from within the same page, remove otherwise)
source: $A.getEl('bannerContainerElementId').parentNode.removeChild($A.getEl('bannerContainerElementId')),
// Specify the path and ID of the banner content to be loaded
// (Only if pulling content from an external page, remove otherwise)
source: 'files/overlays.html #bannerContainerElementId',
// Disable automatic positioning if wishing to use a Style Sheet instead
autoFix: 0,
// Specify that the banner should open as soon as the page loads
autoStart: true,
// Set a class name for the banner top level container element
className: 'banner',
// Specify that the textual content of the banner should automatically be announced to screen reader users when opened
announce: true,
// Choose the container element where the banner will be inserted
isStatic: 'body',
// Choose to prepend the banner instead of replacing the content within the container element
// (This places the banner content at the top of the page in the reading order for screen readers)
prepend: true,
// Set a hidden close link to appear for screen reader users
showHiddenClose: true,
// Remove the hidden close link from the tab order so it doesn't appear when tabbing
displayHiddenClose: false,
// Set the heading level that will be accessible for screen reader users
ariaLevel: 2,
// Run a script after the banner finishes loading
runAfter: function(dc){
// Optionally do stuff
// 'dc' is the Banner AccDC Object
// dc.containerDiv is the DOM node where all banner content is rendered
}
// Other AccDC API properties and methods can go here as well if desired.
}
The invocation statement returns the ID of the newly instantiated Banner AccDC Object, which can be used to programmatically control each banner using JavaScript if desired.
Example:
// Get a reference to the Banner AccDC Object var dc = $A.reg[bannerId]; // Which you can then open dc.open(); // Or close dc.close(); // All other AccDC API properties and methods can be applied here as well.
The sample banners in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the banner. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled banner will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The banners within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accBanner", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes:
A Carousel is a complex control type that is easy to make accessible.
Expected behaviors: The beginning and ending boundaries should be conveyed to screen reader users, content changes should be announced to screen reader users only when a navigation button is manually activated, all navigation buttons should be keyboard accessible and include unique accesskeys for screen reader users, auto cycling should pause when an element within the carousel receives focus or when the mouse is moved into the region, auto cycling should resume when focus moves out of the carousel or when the mouse moves out of the region, and auto cycling should be stoppable from anywhere on the page using the keyboard.
The Carousel Module automates these processes by adding all related event handlers and managing all related rendering procedures using an external XML file for configuration.
<div id="myCarousel"></div>
An external XML file is used to configure and populate each slide of the carousel.
Flat:
<?xml version="1.0" encoding="UTF-8" ?> <carousel role="Slideshow" height="auto" width="auto" className="carouselCls" prevTitle="Previous" nextTitle="Next" slideName="Slide" groupName="" showGroup="" groupPosTop="" btnPText="↑" btnNText="↓" btnPGText="" btnNGText="" isGrouped="no" btnPAccesskey="1" btnNAccesskey="2" btnPGAccesskey="" btnNGAccesskey="" direction="tb" cycle="yes" timer="0" animDelay="1250" forward="yes" hiddenMsg="" > <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> </carousel>
Grouped:
<?xml version="1.0" encoding="UTF-8" ?> <carousel role="Carousel" height="auto" width="auto" className="carouselCls" prevTitle="Previous" nextTitle="Next" slideName="Slide" groupName="Group" showGroup="yes" groupPosTop="yes" btnPText="←" btnNText="→" btnPGText="⇐" btnNGText="⇒" isGrouped="yes" btnPAccesskey="1" btnNAccesskey="2" btnPGAccesskey="3" btnNGAccesskey="4" direction="lr" cycle="yes" timer="5000" animDelay="2000" forward="yes" hiddenMsg="Press Escape to stop automatic cycling" > <group name="Unique Group Name" > <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> </group> <group name="Unique Group Name" > <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> <slide announce="Unique Slide Name" ><![CDATA[ HTML content to render goes here ]]></slide> </group> </carousel>
Important: All attributes must remain within the XML markup. Attributes that are not required may be set to null. E.G. attributeName=""
Carousel attribute definitions:
Group attribute definitions:
Slide attribute definitions:
$A.setCarousel( $A.getEl('myCarousel') , 'path/file.xml' , defaultIndexValue , {
// Configure optional key / value mapping overrides
});
The first parameter is the DOM node container element where the carousel will be inserted.
The second parameter is the file path for the associated XML file.
The third parameter is the default slide index value when the carousel is rendered.
When using a flat carousel, this should be of type 'number', such as 0
When using a grouped carousel, this should be of type 'string', such as '0,0'
The fourth parameter is a key / value map of optional overrides to customize functionality.
Example:
{
// Set the classes for the three floating Div panels that comprise the carousel
// The left Div where the Prev Slide and Prev Group buttons are rendered
lNavCls: 'lNav',
// The center Div where the slides are cycled within a relatively positioned container
contentCls: 'centerContent',
// The right Div where the Next Slide and Next Group buttons are rendered
rNavCls: 'rNav',
// Set the nav button element type
// ('button' is recommended so that the action is automatically triggered when accesskeys are pressed, which doesn't happen for other element types
btnTag: 'button',
// Set the shared class name for all nav buttons
btnCls: 'navButton',
// Set the class name for the Next and Previous Slide buttons
btnSlideCls: 'navSlideButton',
// Set the class name for the Next and Previous Group buttons (if applicable)
btnGroupCls: 'navGroupButton',
// Set the class name for the Group Name container element (Div tag), which is optionally rendered above or below the center slide container
groupNameCls: 'groupName',
// Set the hidden heading level for screen reader users (defaults to 3 if omitted)
ariaLevel: 2,
// Set optional callbacks for the slide rendering action
handlers: {
// Runs every time a new slide completes rendering
complete: function(dc){
// 'this' is the Carousel AccDC Object, and is the same as the 'dc' argument
// The content of the new slide is contained within the DOM node dc.containerDiv
// E.G alert(dc.containerDiv.innerHTML);
// dc.top is the top level AccDC Object for the carousel, which can be used to share data between handler functions.
// Other DOM node properties that are available here
// dc.top.btn.P : The Prev Button DOM node
// dc.top.btn.N : The Next Button DOM node
// dc.top.btn.PG : The Prev Group Button DOM node
// dc.top.btn.NG : The Next Group Button DOM node
// Available state and index values
// dc.groupVal : the current index value of the currently active Group (if applicable)
// dc.groupMax : the maximum number of Groups within the carousel
// dc.slideVal : the current index value of the newly loaded slide (relative to siblings if contained within a Group)
// dc.slideMax : the maximum number of Slides within the Group or carousel (if contained within a flat list)
},
// Runs every time the auto rotation of a carousel stops or resumes rotating
stopStateChange: function(isStopped, dc){
// isStopped or paused = true or false
// Or for granular detection
// dc.isStopped = true or false
// dc.isPaused = true or false
},
// Runs every time the Previous Slide button is clicked
btnPrev: function(ev, dc){
// 'this' is the button element DOM node
// 'dc' is the Carousel AccDC Object
// dc.top is the top level AccDC Object for the carousel, which can be used to share data between handler functions.
// Other DOM node properties that are available here
// dc.btn.P : The Prev Button DOM node
// dc.btn.N : The Next Button DOM node
// dc.btn.PG : The Prev Group Button DOM node
// dc.btn.NG : The Next Group Button DOM node
// Available state and index values
// dc.groupVal : the current index value of the currently active Group (if applicable)
// dc.slideVal : the current index value of the newly loaded slide (relative to siblings if contained within a Group)
// Return false to prevent the previous slide from rendering
},
// Runs every time the Next Slide button is clicked
btnNext: function(ev, dc){
// 'this' is the button element DOM node
// 'dc' is the Carousel AccDC Object
// dc.top is the top level AccDC Object for the carousel, which can be used to share data between handler functions.
// Other DOM node properties that are available here
// dc.btn.P : The Prev Button DOM node
// dc.btn.N : The Next Button DOM node
// dc.btn.PG : The Prev Group Button DOM node
// dc.btn.NG : The Next Group Button DOM node
// Available state and index values
// dc.groupVal : the current index value of the currently active Group (if applicable)
// dc.slideVal : the current index value of the newly loaded slide (relative to siblings if contained within a Group)
// Return false to prevent the next slide from rendering
},
// Runs every time the Previous Group button is clicked
btnPrevG: function(ev, dc){
// 'this' is the button element DOM node
// 'dc' is the Carousel AccDC Object
// dc.top is the top level AccDC Object for the carousel, which can be used to share data between handler functions.
// Other DOM node properties that are available here
// dc.btn.P : The Prev Button DOM node
// dc.btn.N : The Next Button DOM node
// dc.btn.PG : The Prev Group Button DOM node
// dc.btn.NG : The Next Group Button DOM node
// Available state and index values
// dc.groupVal : the current index value of the currently active Group (if applicable)
// dc.slideVal : the current index value of the newly loaded slide (relative to siblings if contained within a Group)
// Return false to prevent the previous group from rendering
},
// Runs every time the Next Group button is clicked
btnNextG: function(ev, dc){
// 'this' is the button element DOM node
// 'dc' is the Carousel AccDC Object
// dc.top is the top level AccDC Object for the carousel, which can be used to share data between handler functions.
// Other DOM node properties that are available here
// dc.btn.P : The Prev Button DOM node
// dc.btn.N : The Next Button DOM node
// dc.btn.PG : The Prev Group Button DOM node
// dc.btn.NG : The Next Group Button DOM node
// Available state and index values
// dc.groupVal : the current index value of the currently active Group (if applicable)
// dc.slideVal : the current index value of the newly loaded slide (relative to siblings if contained within a Group)
// Return false to prevent the next group from rendering
}
},
// Customize the DOM rendering order or add additional controls to the DOM when rendered within the carousel
renderFn: function(parentDiv, leftDiv, centerDiv, bufferDiv, rightDiv, btnPrev, btnNext, isGrouped, btnPrevGroup, btnNextGroup){
parentDiv.appendChild(leftDiv);
parentDiv.appendChild(centerDiv);
centerDiv.appendChild(bufferDiv);
parentDiv.appendChild(rightDiv);
leftDiv.appendChild(btnPrev);
rightDiv.appendChild(btnNext);
if (isGrouped){
leftDiv.appendChild(btnPrevGroup);
rightDiv.appendChild(btnNextGroup);
}
}
}
When the carousel is instantiated, it includes many nested AccDC Objects that are bound using parent / child relationships.
The top level ID for the carousel matches the ID attribute value of the insertion point container element, making it possible to control the carousel programmatically if desired.
Example:
// If the insertion point DIV tag includes id="myCarousel": // Get a reference to the Carousel AccDC Object var dc = $A.reg['myCarousel']; // Which you can then use to access stored data var data = serialize(dc.form); // Or close the carousel and remove it from the DOM dc.close(); // All other AccDC API properties and methods are similarly available if desired. // Also, the following Carousel specific properties and methods are available here too // Set the carousel to a specific slide number, which must be equal to or greater than 0 to match the array index value dc.setSlide(slideNumber); // Or the same when using a grouped carousel dc.setSlide(slideNumber, groupNumber); // Programmatically stop auto cycling of a carousel dc.enableAuto(false); // Programmatically restart auto cycling of a carousel dc.enableAuto(true); // Return the current stopped state of an auto rotating carousel var isStopped = dc.isStopped();
Important: The Carousel AccDC Object consists of many nested AccDC Objects which act as moving parts, similar to cogwheels within the construct.
So when dc.close() is used to close the carousel, it, including all of its nested objects, are destroyed completely.
(This means that stored data will no longer be available programmatically after a carousel is closed.)
This is done to ensure that duplication and scheduling conflicts don't arise when dynamic content panels are swapped, causing the same carousel structure to be reloaded.
The sample carousels in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled carousel will be accessible.
Drag and Drop isn't called for much as part of a general feature set, but it's good to know how to make this functionality accessible for both screen reader and keyboard only users.
Expected behaviors: All draggable objects must be accessible from the keyboard with or without a screen reader running, and hidden links should be used to identify draggable objects and the location of drop zones.
The Drag and Drop Module automates these processes by adding all related event handlers and managing all related rendering procedures.
$A.setDragAndDrop({
// Configure functionality using a key / value map
});
The first parameter configures drag and drop functionality using a key / value map.
Example:
{
// Specify the draggable objects using a CSS Selector
setDrag: 'ul#options li > img',
// Specify the initial drop zone
setDrop: 'div.chosenBooks',
// CSS Selector or DOM node that specifies an optional strategic focus point where programmatic focus will return after a drop action completes
returnFocusTo: 'div.chosenBooks h3',
// Set the context node
root: document,
// Now, since the hidden links need custom link text for each draggable item,
// we're going to recursively query the data-label attribute for every image and return it
setName: function(obj){
// 'obj' is the object that matches the CSS Selector above in 'setDrag'
return $A.getAttr(obj, 'data-label');
},
// Set the initial styles for the morphed AccDC Object, which will need absolute positioning
cssObj:
{
position: 'absolute',
zIndex: 1
},
// Prevent block formatting when surrounding divs are added
displayInline: true,
// Run script before the AccDC Object opens
runBefore: function(dc){
// Do stuff
},
// Run script after the AccDC Object opens
runAfter: function(dc){
// Do stuff
},
// Configure drag and drop event handlers
on: {
// Fire when the mouse moves a minimum distance.
dragStart: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
},
// Fire every time the mouse moves when dragging.
drag: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
},
// Fire when the dragged element moves within the tolerance of a drop target element.
dropStart: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
},
// Fire when the dragged element is dropped within the tolerance of a drop target element.
drop: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
},
// Fire when the dragged element moves out of the tolerance of a drop target element.
dropEnd: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
},
// Fire after all other drag and drop handlers have fired.
dragEnd: function(ev, dd, dc){
// 'ev' is the event object
// 'dd' is the Drag and Drop custom event object
// 'dc' is the AccDC Object for the draggable object
}
},
// Restrict draggability, since there's no point in having stuff wiz around everywhere...
confineTo: 'div.booksWrapper',
// Set the drop animation time length for keyboard users in milliseconds
duration: 2000,
// Set keywords for screen reader and keyboard only users
dragText: 'Move',
toText: 'to',
// IMPORTANT: All dropTarget elements must include a data-label attribute to specify a unique name for the drop region for screen reader and keyboard only users.
// View the Coding Arena HTML markup for examples.
actionText: 'Dragging',
// Override default relative positioning to use absolute instead
// Effects only the hidden drag links when they receive focus
ddCSS:
{
position: 'absolute',
zIndex: 10
},
// Set class names for the drag links
dragClassName: 'ddLink'
}
The properties and methods of the 'dd' drag and drop custom event object are as follows:
For drag events:
For drop events:
Footnotes are simple control types that are easy to make accessible.
Expected behaviors: Provide a link as the footnote that jumps to the footnote text, provide a link at the footnote text that returns focus back to the triggering element (and account for multiple footnote links that lead to the same footnote text), and provide meaningful textual equivalents for screen reader users.
The Footnotes Module automates these processes by creating all necessary anchor elements, adding all related event handlers, and managing keyboard focus appropriately.
Footnote text in the body:
<span class="accFootnote" data-footnote="footnotePointer1">My body text</span>
A SPAN tag should be used to surround the word or phrase that you want to designate as a footnote within the body content.
Required attributes for Footnote SPANs in the body:
Important: When the footnotes are parsed using the class name, a numerical index link is generated and appended to the footnote SPAN tag.
Footnote Text nodes in the footer:
<span id="footnotePointer1"></span>
An empty SPAN tag should be used to set the focus point of the Footnote Text node in the footer, which is where focus will be moved to when the footnote link in the body is activated.
The Footnote Text SPAN tag must be placed just before the footnote text in the source code order, since this is where the Footnote Back Link will be inserted.
(This is also where focus is moved to when a footnote link in the body is activated, which must be before the relevant footnote text, and not after.)
The Footnote Text SPAN tag must be empty, and must not surround the footnote text. Doing so will cause the inserted Back Link to appear after the footnote text, instead of before it, as expected.
Required attributes for Footnote Text SPANs in the footer:
The following attributes are handled automatically by the Footnotes Module:
$A.setFootnotes('.accFootnote', document, {
// Configure functionality key / value mappings
});
The first parameter is a CSS Selector that specifies all footnote SPAN tags in the body.
The second parameter is the context DOM node where footnote SPANs will be queried using the CSS Selector declared in parameter one. (This makes it possible to query footnotes contained within iFrame documents)
The third parameter configures footnote functionality using a key / value map.
Example:
{
// Set the tooltip text for the footnote (this will also be the accessible name for screen reader users)
fnText: 'Footnote',
// Set the footnote character or text that will comprise the visual link text for returning footnotes
fnChar: '†',
// Set the tooltip text for the footnote back links (this will also be the accessible name for screen reader users)
backText: 'Back to Footnote'
}
The sample footnotes in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled footnotes will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The footnotes within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accFootnote", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for footnote SPANs in the body:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes:
Error Tooltips provide a simple way to validate user input prior to server side interaction.
Dynamic Help Tooltips work in a similar fashion, by suggesting responses that must also pass validation.
Both fulfill the same role, but on opposite spectrums.
Error Tooltips occur after a form field loses focus, which is when validation occurs.
Dynamic Help Tooltips validate user input as the interaction occurs, so that responses can be adjusted before focus is moved to the next field.
The Form Field Validation Module automates these processes by adding all related event handlers and managing all related rendering procedures.
Any standard form field.
Examples:
<label for="field1"> My Text Field: </label> <input type="text" id="field1" name="whatever1" /> <label for="field2"> My Select : </label> <select id="field2" name="whatever2"> <option value="v0"> Option One </option> <option value="v1"> Option Two </option> </select> <input type="checkbox" id="field3" name="whatever3" /> <label for="field3"> My Checkbox </label> <input type="radio" id="field4" name="whatever4" /> <label for="field4"> My Radio Button </label>
The following attributes are handled automatically by the Form Field Validation Module:
$A.setFormFields( FormElementDOM-Node , {
'formFieldId1': {
// Configure error handling for the form field with id="formFieldId1"
},
'formFieldId2': {
// Configure error handling for the form field with id="formFieldId2"
}
}, function(ev){
// 'ev' is the onSubmit event object for the form element passed in parameter one
// 'this' is the form element
// Optionally do stuff before the form is submitted
// use ev.preventDefault() to cancel if desired
});
The first parameter is the form element where the onSubmit event is attached.
The second parameter configures form field bindings using a key / value map.
Example:
{
// Configure an error handling tooltip for a form field with a specific ID attribute value
'formFieldId1': {
errorText: 'Initial error text to be displayed',
// Fire every time the field loses focus
validate: function(ev, dc){
// 'this' is the form field to be validated
// 'dc' is the Tooltip AccDC Object
// All other AccDC API properties and methods apply to the 'dc' object as well
// return true to pass validation, or false to fail
},
// Optionally choose to hide or show the tooltip visually
// false is set by default if omitted
hideError: false,
// Set a class to be toggled when an error is detected
// This will be bound to the dc.triggerObj DOM node, or optionally to the dc.targetObj or dc.classObj DOM node instead if declared.
// 'validateError' is set by default if omitted
toggleClass: 'validateError',
overrides: {
// Change the beginning and ending boundary role text for screen reader users
role: 'error',
// Set a class for the tooltip container
className: 'errorTooltip',
// Change the DOM insertion point to another DOM node by setting targetObj.
// The triggering Input field is used by default if omitted
targetObj: DOM-Node,
// Set a node where the toggleClass property value will be toggled when validation fails
// The triggering Input field or targetObj element is used by default if omitted
classObj: DOM-Node,
// Optionally set the element where visual positioning calculations will be bound to
posAnchor: DOM-Node
// Additional AccDC API properties and methods to set as functionality and behavior overrides go here as well
}
},
// Configure a dynamic help tooltip for a form field with a specific ID attribute value
'formFieldId2': {
helpText: 'Initial help text to be displayed',
// Fire every time the value changes
validate: function(ev, dc){
// 'this' is the form field to be validated
// 'dc' is the Tooltip AccDC Object
// dc.source can be used to dynamically change the tooltip content (HTML markup is accepted)
// dc.open() will reopen the tooltip and display the updated content
// dc.close() will close the tooltip if desired
// All other AccDC API properties and methods apply to the 'dc' object as well
// return true to pass validation, or false to fail
},
// Assign a class to be toggled
toggleClass: 'passedValidation',
// Set the above class to be toggled only when validation is true, and not when false
togglePassed: true,
overrides: {
// Change the beginning and ending boundary role text for screen reader users
role: 'help',
// Set a class for the tooltip container
className: 'helpTooltip',
// Change the DOM insertion point to another DOM node by setting targetObj.
// The triggering Input field is used by default if omitted
targetObj: DOM-Node,
// Set a node where the toggleClass property value will be toggled when validation passes or fails
// (Depends whether 'togglePassed' is set to true or false)
// The triggering Input field or targetObj element is used by default if omitted
classObj: DOM-Node,
// Optionally set the element where visual positioning calculations will be bound to
posAnchor: DOM-Node
// Additional AccDC API properties and methods to set as functionality and behavior overrides go here as well
}
}
}
The third parameter is an optional onSubmit handler that will run just before the form is submitted after validation passes.
The sample tooltips in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled tooltips will be accessible.
All form fields must be explicitly labeled to ensure accessibility for the highest percentage of people.
Explicit labelling can be achieved using the LABEL and INPUT elements, by matching the LABEL tag's For attribute with the INPUT tag's Id attribute,
or by setting the Title attribute on the INPUT tag with an informative label,
or by setting the aria-label attribute on the INPUT tag with an informative label,
or by setting the aria-labelledby attribute on the INPUT tag that references the ID of an informative label.
The advantage of using an explicitly associated LABEL element and INPUT tag, is that mouse users can click the label text and automatically activate the form field that it applies to. Voice navigation software also uses explicit LABEL/INPUT tag associations to aid navigation.
This type of functionality does not occur when using the Title attribute or ARIA to explicitly associate a label.
When an INPUT element has an explicitly associated LABEL tag, a Title attribute should not be included. Screen readers often use an order of precedence when reading form field labels, and will often announce one or the other, but not both.
When a form field has an explicit LABEL, additional information can also be associated with the form field using aria-describedby, which will automatically be announced to screen reader users when focus is set to that field.
Example:
<label for="field1"> My Text Field: </label> <input type="text" id="field1" aria-describedby="additional1" name="whatever" /> <span id="additional1"> Supplementary Text </span>
Important: When implementing supplementary text to be announced for screen reader users, never use "display:none" or "visibility:hidden" to hide the text that is being announced. Doing so will make it impossible for screen reader users to browse the supplementary text using the arrow keys if clarification is needed. If you wish to hide the supplementary text from sighted users, use offscreenText instead.
A Modal is a relatively simple control type, and can easily be made accessible.
Expected behaviors: Ensure that the background content is hidden from screen reader users, ensure that the beginning and ending boundaries are conveyed to screen reader users, make sure the modal can be closed from the keyboard, and ensure that circular tabbing confines keyboard focus within the modal content.
The Modal Module automates these processes by instantiating the content as a Modal AccDC Object, which can be configured and controlled programmatically if desired to enhance functionality.
For the triggering element:
<a href="#" id="modalTrigger"> Triggering Element </a>
(A triggering element is not actually required)
For the modal container element:
<div id="modalContainerId"> Modal content goes here. </div>
Required HTML5 attributes for the modal container element:
Also, when Implementing a Close link or button, the className must match the "closeClassName" property within the JavaScript invocation statement. (If not explicitly set, the default value "lbClose" will be set by default, and should be used for all Close links or buttons) Doing so will automatically bind the AccDC Close Methods with this element, and return keyboard focus properly when the AccDC Object is closed.
The following attributes are handled automatically by the Modal Module:
var modalId = $A.setModal({
// Configure functionality key / value mappings
});
The first parameter configures modal functionality using a key / value map.
Example:
{
// Set a unique ID for the modal AccDC Object, which can be referenced through $A.reg['uniqueId']
id: 'uniqueId',
// Set the screen reader accessible boundary text values
role: 'Modal',
// Set a triggering element using either the DOM node or a CSS Selector
// (Only if a triggering element is present, remove otherwise)
trigger: '#modalTrigger',
// Prevent focus from returning to a triggering element
// (Only if a triggering element is not present, remove otherwise)
returnFocus: false,
// Specify that literal content is to be rendered
// (Only if pulling content from within the same page, remove otherwise)
mode: 0,
// Use removeChild to grab the desired modal content from within the document
// This is important to prevent ID attribute conflicts later
// (Only if pulling content from within the same page, remove otherwise)
source: $A.getEl('modalContainerId').parentNode.removeChild($A.getEl('modalContainerId')),
// Specify the file path and ID attribute of the modal container element
// (Only if pulling content from an external page, remove otherwise)
source: 'files/modal.html #modalContainerId',
// Set the class name for the top level container element
className: 'modal',
// Set the class name for the screen reader accessible close link
// This must match the class name for any close links or buttons within the modal content, which will cause Close Method Binding to automatically occur when the content is rendered.
closeClassName: 'lbClose',
// Set the heading level that will be accessible for screen reader users
// This is set to 1, since a modal constitutes an independent content section equal to a standalone page
ariaLevel: 1,
// Run script after the Modal AccDC Object finishes loading
runAfter: function(dc){
// 'dc' is the Modal AccDC Object
// Set a background Div for the modal, so it will appear as a lightbox
dc.backdrop = $A.createEl('div', null, null, 'modalBackdrop', document.createTextNode(' '));
// Now insert the backdrop Div before the Modal AccDC Object top level container
dc.accDCObj.parentNode.insertBefore(dc.backdrop, dc.accDCObj);
// Now configure content bindings within the modal
// dc.containerDiv is the DOM node where the newly rendered modal content is contained
// All other AccDC API properties and methods are similarly available for the 'dc' object
},
// Run script after the Modal AccDC Object finishes closing
runAfterClose: function(dc){
// Remove the backdrop Div
if (dc.backdrop)
dc.backdrop.parentNode.removeChild(dc.backdrop);
}
// (Other AccDC API properties and methods can be declared here also to customize functionality and behavior)
}
Every modal is registered as an AccDC Object, the ID of which is returned by the JavaScript invocation statement.
This means that you can programmatically control each modal using JavaScript.
Example:
// Get a reference to the Modal AccDC Object using the ID stored in the modalId variable var dc = $A.reg[modalId]; // Now invoke the modal dc.open(); // Or close the modal dc.close(); // All other AccDC API properties and methods can be applied here as well.
A triggering element for a modal is not required, but when one is present, you should always use an active element for this purpose to ensure accessibility for both screen reader and keyboard only users.
Within the Coding Arena samples, these are standard links (A tags with an Href attribute). However, you can use whatever type of triggering element you wish, a standard link, button, or image link, with any type of styling.
The sample modals in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the modal. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled modal will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The modals within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accModal", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes for the triggering element:
Do not use aria-haspopup.
It might sound like a good idea to notify screen reader users that a 'Popup' is attached by adding the attribute aria-haspopup="true" to the triggering element, but this is not a good idea.
Screen readers announce different feedback based on the various combinations of element types and ARIA roles in the markup, which can lead to confusion and misrepresent the purpose of the feature altogether.
Examples:
<!-- Triggering Element One JAWS 13 and 14 announces as "Has Popup" NVDA2013 announces as "SubMenu" --> <a href="#" aria-haspopup="true"> Triggering Element One </a> <!-- Triggering Element Two JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <a href="#" role="button" aria-haspopup="true"> Triggering Element Two </a> <!-- Triggering Element Three JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <button aria-haspopup="true"> Triggering Element Three </button>
In short, don't use aria-haspopup unless you are triggering a menu.
A Popup is a relatively simple control type, and can easily be made accessible.
Expected behaviors: Ensure that the beginning and ending boundaries are conveyed to screen reader users, make sure the popup can be closed from the keyboard, and ensure that focus moves appropriately when the popup opens and closes.
The Popup Module automates these processes by instantiating the content as a Popup AccDC Object, which can be configured and controlled programmatically if desired to enhance functionality.
For the triggering element:
<a href="#" id="popupTrigger"> Triggering Element </a>
For the popup container element:
<div id="popupContainerId"> Popup content goes here. </div>
When Implementing a Close link or button, the className must match the "closeClassName" property within the JavaScript invocation statement. (If not explicitly set, the default value "popupClose" will be set by default, and should be used for all Close links or buttons) Doing so will automatically bind the AccDC Close Methods with this element, and return keyboard focus properly when the AccDC Object is closed.
var popupId = $A.setPopup({
// Configure functionality key / value mappings
});
The first parameter configures popup functionality using a key / value map.
Example:
{
// Set a unique ID for the Popup AccDC Object, which can be referenced through $A.reg['uniqueId']
id: 'uniqueId',
// Set the screen reader accessible boundary text values
role: 'Popup',
// Set a triggering element using either the DOM node or a CSS Selector
trigger: '#popupTrigger',
// Specify that literal content is to be rendered
// (Only if pulling content from within the same page, remove otherwise)
mode: 0,
// Use removeChild to grab the desired popup content from within the document
// This is important to prevent ID attribute conflicts later
// (Only if pulling content from within the same page, remove otherwise)
source: $A.getEl('popupContainerId').parentNode.removeChild($A.getEl('popupContainerId')),
// Specify the file path and ID attribute of the popup container element
// (Only if pulling content from an external page, remove otherwise)
source: 'files/popup.html #popupContainerId',
// Position the popup on the right of the triggering element
autoPosition: 3,
// Move the Popup AccDC Object 10px to the right, and 20px up when opened
offsetLeft: 10,
offsetTop: -20,
// Set the class name for the top level container element
className: 'popup',
// Set the class name for the screen reader accessible close link
// This must match the class name for any close links or buttons within the popup content, which will cause Close Method Binding to automatically occur when the content is rendered.
closeClassName: 'popupClose',
// Set a visually hidden close link for screen reader users to appear at the end of the popup content
showHiddenClose: true,
// Set the visually hidden close link to appear onFocus (required for 508 compliance if no other keyboard accessible close method is available)
displayHiddenClose: true,
// Set the heading level that will be accessible for screen reader users
ariaLevel: 2,
// Run script after the Popup AccDC Object finishes loading
runAfter: function(dc){
// 'dc' is the Popup AccDC Object
// dc.containerDiv is the DOM node where the newly rendered popup content is contained
// All other AccDC API properties and methods are similarly available for the 'dc' object
},
// Run script after the Popup AccDC Object finishes closing
runAfterClose: function(dc){
// Optionally do stuff
}
// (Other AccDC API properties and methods can be declared here also to customize functionality and behavior)
}
Every popup is registered as an AccDC Object, the ID of which is returned by the JavaScript invocation statement.
This means that you can programmatically control each popup using JavaScript.
Example:
// Get a reference to the Popup AccDC Object using the ID stored in the popupId variable var dc = $A.reg[popupId]; // Now invoke the popup dc.open(); // Or close the popup dc.close(); // All other AccDC API properties and methods can be applied here as well.
Regarding the triggering element, you should always use an active element for this purpose to ensure accessibility for both screen reader and keyboard only users.
Within the samples, these are standard links (A tags with an Href attribute). However, you can use whatever type of triggering element you wish, a standard link, button, or image link, with any type of styling. There must be an active element as a triggering element though, to ensure accessibility.
The sample popups in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like. This is demonstrated within the "Shell" folders, where there is no CSS styling for the popup. This is also useful as a practice template for trying out different styling designs with custom content.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled popup will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The popups within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accPopup", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes for the triggering element:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes for the triggering element:
Do not use aria-haspopup.
It might sound like a good idea to notify screen reader users that a 'Popup' is attached by adding the attribute aria-haspopup="true" to the triggering element, but this is not a good idea.
Screen readers announce different feedback based on the various combinations of element types and ARIA roles in the markup, which can lead to confusion and misrepresent the purpose of the feature altogether.
Examples:
<!-- Triggering Element One JAWS 13 and 14 announces as "Has Popup" NVDA2013 announces as "SubMenu" --> <a href="#" aria-haspopup="true"> Triggering Element One </a> <!-- Triggering Element Two JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <a href="#" role="button" aria-haspopup="true"> Triggering Element Two </a> <!-- Triggering Element Three JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <button aria-haspopup="true"> Triggering Element Three </button>
In short, don't use aria-haspopup unless you are triggering a menu.
A Progress Bar control is a relatively simple HTML5 control that, nevertheless, does require a specific implementation in order to work correctly in a backwards compatible manner with Internet Explorer 8.
The Progress Bar module automates this process by instantiating a Progress Bar control that can be programmatically set at runtime as values change.
Unobtrusive:
(No HTML markup is needed)
Inline:
<div id="pbTargetZone"></div>
The following attributes are handled automatically by the Progress Bar Module:
var myProgressBar = $A.setProgressBar({
// Configure functionality using a key / value map
});
The first parameter configures Progress Bar functionality using a key / value map.
Example:
{
// Set a unique ID, which will also be the ID attribute value for the 'progress' element when rendered
id: 'progressbar1',
// Set the boundary text for screen reader users
role: 'Download',
// Set initial values for the progress bar, values may be of type Int or Float
config: {
value: 0,
max: 100
},
// Specify the container element where the Progress Bar AccDC Object will be inserted
// (Only if pointing to the ID of a target zone container element, remove otherwise)
isStatic: '#pbTargetZone',
// Specify the container element where the unobtrusive Progress Bar AccDC Object will be inserted
// (Only if no target zone container tag is present, remove otherwise)
isStatic: 'body',
// Also, prepend the progress bar content to the content already contained within the body element
// This also places it at the top of the page for screen reader users
prepend: true,
// Set the class name for the top level container Div that surrounds the 'progress' element
className: 'progressBar',
// Load the Progress Polyfill script after the progress bar is rendered for cross-browser compatibility
// (The accompanying CSS file must also be included in the header of the page)
runJSAfter: ['js/progress-polyfill.min.js'],
// Run script after the progress bar finishes rendering
runAfter: function(dc){
// Optionally do something
// dc.source is the DOM node for the rendered 'progress' element
},
// Run script after the progress bar finishes closing
runAfterClose: function(dc){
// Optionally do something
}
// Other AccDC API properties and methods can be applied here as well if desired
}
The function "$A.setProgressBar" returns the instantiated AccDC Object for the progress bar, which can then be controlled as follows:
// Render the Progress Bar myProgressBar.open(); // Update the Progress Bar with a new value myProgressBar.set(50); // Then close the Progress Bar after the process has completed myProgressBar.close();
The sample Progress Bars in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
Instructions for changing the visual appearance of the 'progress' element are discussed in the article "Cross Browser HTML5 Progress Bars In Depth".
To ensure proper rendering across various browsers, the Progress Bar Module requires the following dependencies:
A Scrollable Div is a very simple control type, which can easily be made accessible.
Expected behaviors: Ensure that the scrollable container element receives keyboard focus, and ensure that the Up/Down/Left/Right arrow keys and the PageUp/PageDown and the Home/End keys scroll content appropriately.
The Scrollable Div Module automates these processes by making the scrollable container keyboard accessible.
<div id="scrollableDivId"> <div> Scrollable content goes here. </div> </div>
The following attributes are handled automatically by the Scrollable Div Module:
$A.makeScrollable(scrollableDivDOM_Node, 'textMessageForScreenReaderUsers');
The first parameter is the DOM node of the scrollable div container (with 'overflow:auto' in the CSS).
The second parameter is the text string that will be announced to screen reader users the first time that focus moves into the Scrollable Div. (This message alerts VoiceOver users that the region is scrollable.) 'Scrollable Region' is set by default if no value is specified.
The sample Scrollable Divs in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled Scrollable Div will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The Scrollable Divs within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accScrollable", then configures the same module declaration as previously described using these HTML5 attributes.
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes:
Do not use aria-haspopup.
It might sound like a good idea to notify screen reader users that a 'popup' is attached by adding the attribute aria-haspopup="true" to the triggering element (if applicable), but this is not a good idea.
Screen readers announce different feedback based on the various combinations of element types and ARIA roles in the markup, which can lead to confusion and misrepresent the purpose of the feature altogether.
Examples:
<!-- Triggering Element One JAWS 13 and 14 announces as "Has Popup" NVDA2013 announces as "SubMenu" --> <a href="#" aria-haspopup="true"> Triggering Element One </a> <!-- Triggering Element Two JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <a href="#" role="button" aria-haspopup="true"> Triggering Element Two </a> <!-- Triggering Element Three JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <button aria-haspopup="true"> Triggering Element Three </button>
In short, don't use aria-haspopup unless you are triggering a menu.
Additionally, no ARIA attributes are necessary to make a Scrollable Div accessible for screen reader users.
VoiceOver instructions for use on iOS touch screen devices:
To navigate the content of a Scrollable Div using VoiceOver, use the Rotator (turn three fingers like turning a knob) to select Line Mode, then use one finger to swipe up and down within the scrollable content to navigate.
(Credit goes to David Hilbert Poehlman for providing VoiceOver rotator navigation technique instructions.)
A Tooltip is a relatively simple control type, which can easily be made accessible.
Expected behaviors: Ensure that the beginning and ending boundaries are conveyed to screen reader users, and make sure the Tooltip is accessible from the keyboard.
The Tooltip Module automates these processes by instantiating the content as a Tooltip AccDC Object, which can be configured and controlled programmatically if desired to enhance functionality.
For the triggering element:
<a href="#" id="tooltipTrigger1"> Triggering Element </a>
Or
<input type="..." id="tooltipTrigger2" title="Field name if no Label tag is associated" />
Or
<select id="tooltipTrigger3" title="Field name if no Label tag is associated"> <option value="0"> Option One </option> <option value="1"> Option Two </option> </select>
For the tooltip container element:
<div id="tooltipContainerId"> Tooltip content goes here. </div>
var tooltipId = $A.setTooltip({
// Configure functionality key / value mappings
});
The first parameter configures tooltip functionality using a key / value map.
Example:
{
// Set a unique ID for the Tooltip AccDC Object, which can be referenced through $A.reg['uniqueId']
id: 'uniqueId',
// Set the role name for the container
role: 'tooltip',
// Set the triggering element using a DOM node or a CSS Selector
trigger: '#tooltipTrigger1',
// Set an optional time delay in milliseconds
wait: 1500,
// Specify that literal content is to be rendered
// (Only if pulling content from within the same page, remove otherwise)
mode: 0,
// Use removeChild to grab the desired Tooltip content from within the document
// This is important to prevent ID attribute conflicts later
// (Only if pulling content from within the same page, remove otherwise)
source: $A.getEl('tooltipContainerId').parentNode.removeChild($A.getEl('tooltipContainerId')),
// Set a file path to pull the Tooltip content from and reference the container element ID
// (Only if pulling content from an external page, remove otherwise)
source: 'files/tooltip.html #tooltipContainerId',
// Position the Tooltip on the right of the triggering element
autoPosition: 3,
// Move the Tooltip AccDC Object 10px to the right when opened
offsetLeft: 10,
// Set the class name for the top level container element
className: 'tooltip'
// (Other AccDC API properties and methods can be declared here also to customize functionality and behavior)
}
Every tooltip is registered as an AccDC Object, the ID of which is returned by the JavaScript invocation statement.
This means that you can programmatically control each tooltip using JavaScript.
Example:
// Get a reference to the Tooltip AccDC Object using the ID stored in the tooltipId variable var dc = $A.reg[tooltipId]; // Now change the content of the tooltip dc.source = 'Hello World'; // All other AccDC API properties and methods can be applied here as well.
The sample tooltips in the Coding Arena are styled to look a certain way for the demo, but it doesn't actually matter what they look like.
When applying new styles, simply ensure that sufficient color contrast is observed for low vision users, and a focus outline clearly shows which elements have focus, and your newly styled tooltip will be accessible.
Bootstrapping is designed to handle common control types that span multiple pages with similar setup configurations.
The tooltips within the Bootstrap folders are configured using HTML5 "data-" attributes within the HTML markup.
When the Bootstrap Module ("accdc_bootstrap.js") is executed, it parses the newly loaded DOM, recognizes the class "accTooltip", then configures the same module declaration as previously described using these HTML5 attributes.
Available HTML5 attributes:
Additional HTML5 attributes can be added to enhance functionality by editing the file "accdc_bootstrap.js".
Required attributes:
When an A tag is used as the triggering element, it must adhere to the following:
Do not use aria-haspopup.
It might sound like a good idea to notify screen reader users that a 'Popup' is attached by adding the attribute aria-haspopup="true" to the triggering element, but this is not a good idea.
Screen readers announce different feedback based on the various combinations of element types and ARIA roles in the markup, which can lead to confusion and misrepresent the purpose of the feature altogether.
Examples:
<!-- Triggering Element One JAWS 13 and 14 announces as "Has Popup" NVDA2013 announces as "SubMenu" --> <a href="#" aria-haspopup="true"> Triggering Element One </a> <!-- Triggering Element Two JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <a href="#" role="button" aria-haspopup="true"> Triggering Element Two </a> <!-- Triggering Element Three JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <button aria-haspopup="true"> Triggering Element Three </button>
In short, don't use aria-haspopup unless you are triggering a menu.
The concept of Web Chat seems complicated, but it's actually quite easy to make accessible for screen reader and keyboard only users.
This may not be readily apparent by reading the JavaScript code for the chat demo in the Coding Arena however, so I'll outline the concepts that make it accessible here, to simplify things.
Now, here is where the magic is for screen reader users. Whenever new messages arrive, they are automatically announced. This is accomplished using the $A.announce() method, which automatically queues incoming messages using Unobtrusive Announcement to prevent speech interruption. It also can be set to ignore repetitive messages by passing true as the second parameter.
Example:
$A.announce(LastMSG-DOM-Node, true);
The $A.announce() method is also prototyped to the String object, so it can be invoked by returning strings as well for storage if desired.
Example:
var msgHistory = [], msgTextString = 'Howdy!'; msgHistory.push( msgTextString.announce() );
Which will both store the string contained in the variable msgTextString and announce it to screen reader users at the same time.
When a chat dialog is closed, the following method may be invoked:
String.announce.clear();
This will clear the queue so that message announcement does not continue to occur after the chat dialog is closed.
The AccDC Announce method has been tested successfully using JAWS 11-14, NVDA, and VoiceOver, in Internet Explorer 8-9, Firefox, Chrome, and Safari with applicable screen readers.
$A.announce( StringOrDOMNode , SuppressRepeat?<true/false> , isAggressive?<true/false> );
Or
var myString = anotherString.announce();
The first parameter is a DOM node or text string to be announced. (Repetitive messages will automatically be queued for announcement.)
The second parameter is a Boolean value that specifies whether the announcement of repeat message text is automatically suppressed.
If set to true, repetitive text will not be announced to screen reader users.
False is set by default if no value is specified.
The third parameter is a Boolean value that specifies whether aggressive announcement will be used to announce text.
If set to true, prior speech output will be interrupted and the latest text message will be forcibly announced. This will occur regardless which window currently has focus, and is not desirable in most cases.
False is set by default if no value is specified.
Manually clear the message queue
String.announce.clear();
Access the last message that was announced
var last = String.announce.lastMsg;
Adjust the initial delay in milliseconds when the "$A.announce()" method queues messages to be announced sequentially
String.announce.baseDelay = 2000;
Adjust the delay in milliseconds when a message using "$A.announce()" contains two or more words including punctuation.
String.announce.charMultiplier = 160;
Important: Unobtrusive Announcement should only be used sparingly, and not for everything.
When too many things are announced on the same page, it is difficult for screen reader users to differentiate between what is being announced, and what is being navigated using the arrow keys. This is because the same voice is used for both, with no distinction.
Even though ARIA stands for Accessible Rich Internet Applications, the improper use of ARIA will actually cause accessibility issues for screen reader users.
Important things to be aware of:
Improper use of ARIA examples:
Example 1: Phantom form fields
<form> <div id="lgnd"> Contact Details </div> <div role="textbox" aria-label="Your full name" aria-required="true" aria-describedby="lgnd"> <input type="text" name="full_name" /> </div> <div role="textbox" aria-label="Your email address" aria-required="true" aria-describedby="lgnd"> <input type="text" name="email_address" /> </div> </form>
Since the use of role="textbox" is used to surround a native form field, JAWS sees two form fields when using the Arrow keys to navigate up and down the page, causing confusion for screen reader users.
Similarly, since all supporting attributes such as aria-label, aria-describedby, and aria-required are applied to the wrong elements, they are not accessible as a result.
Example 2: Unreadable content
<table role="tree"> <tr role="treeitem"> <td> Name: </td> <td> Bryan Garaventa </td> </tr> <tr role="treeitem"> <td> Title: </td> <td> Bryan Garaventa - Resume </td> </tr> <tr role="treeitem"> <td> File Type: </td> <td> PDF </td> </tr> </table>
The use of role="tree" and role="treeitem" on this table, literally makes it impossible to read the table content using JAWS.
Example 3: Mixing roles
<div role="tablist"> <div role="tab"> <h2> <a href="#"> Link One </a> </h2> </div> <div role="tab"> <h2> <a href="#"> Link Two </a> </h2> </div> <div role="tab"> <h2> <a href="#"> Link Three </a> </h2> </div> </div>
Since screen readers convey certain role types (such as Tabs) as form controls, the nesting of additional active elements confuses screen reader output.
Example 4: Confusing feedback
<textarea title="Status" aria-haspopup="true"></textarea> <textarea title="Comment" aria-expanded="true"></textarea>
In the case of aria-haspopup on the edit field, only "Has Popup" is announced by JAWS, which is confusing. "Has Popup" does not convey what the purpose of the popup is, nor does it indicate how to invoke it. NVDA announces "Edit SubMenu", which is even more confusing.
In the case of aria-expanded on the edit field, "Edit Expanded" is announced by screen readers, which is superfluous. The content of all edit fields, even when scrolled off screen visually, is always visible to screen reader users, so announcing expanded means nothing to screen reader users.
Conclusion
Whenever ARIA is applied, it must be thoroughly tested using JAWS in Internet Explorer and using NVDA in Firefox. These are the two most widely used Windows based screen readers in the world. JAWS is hard coded to work best in Internet Explorer, and NVDA is hard coded to work best in Firefox.
If mobile support is needed, VoiceOver on iOS devices is the most widely used screen reader that should be used for testing. TalkBack on the Android is the second most widely used.
Important: Even when ARIA is implemented correctly and precisely according to the specification, if adding certain ARIA attributes causes accessibility issues for screen reader users to occur, then they should not be used.
The attribute aria-haspopup should only be used on triggering elements that open menus. Otherwise, the presence of the attribute will only misrepresent the popup type to screen reader users.
Examples:
<!-- Triggering Element One JAWS 13 and 14 announces as "Has Popup" NVDA2013 announces as "SubMenu" --> <a href="#" aria-haspopup="true"> Triggering Element One </a> <!-- Triggering Element Two JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <a href="#" role="button" aria-haspopup="true"> Triggering Element Two </a> <!-- Triggering Element Three JAWS 13 and 14 announces as "Menu" NVDA2013 announces as "Menu Button SubMenu" --> <button aria-haspopup="true"> Triggering Element Three </button>
The attribute role="presentation" should only be used in very limited circumstances, and only when it is desirable to suppress the role of an element for screen reader users.
Many element types have particular roles that are automatically conveyed to screen reader users.
Examples include headings, links, buttons, images, lists, frames, tables, form fields, and many others. All of which have specific relevance for screen reader users, who depend on the identification of these roles to navigate reliably within web pages.
When role="presentation" is added to the markup of such an element, it manually overrides this role mapping in the browser, and prevents the screen reader from identifying or even interacting with the element in the expected manner.
Example 1: Headings
<h2 role="presentation"> Key Section Heading </h2>
It is now impossible for screen reader users to navigate to the heading using the H and Shift+H key commands, nor is the text identified as a heading while browsing down the page using the arrow keys.
Example 2: Links and Buttons
<a href="#" role="presentation"> Triggering Element </a> <button role="presentation"> Triggering Element </button>
It is now impossible for screen reader users to identify these elements as actionable elements during navigation.
Example 3: Tables
<table role="presentation"> <tr> <th scope="col"> Product </th> <th scope="col"> Quantity </th> </tr> <tr> <td> Doorknob </td> <td> 2000 </td> </tr> </table>
It is now impossible for screen reader users to navigate the data table using table navigation commands.
Whenever role="presentation" is added to HTML markup, it must always be tested using JAWS, NVDA, and VoiceOver (if applicable) to ensure that the element type remains accessible for screen reader users.
When JAWS interacts with the Virtual Buffer, making it possible for screen reader users to navigate from the top of the page to the bottom using the Down arrow key, it will not automatically trigger the onFocus handler.
When you do the same using NVDA however, it will automatically trigger the onFocus handler.
This means that, any elements that cause specific actions to occur, such as simulated Tab controls, simulated Radio Button controls, or any other control type that uses onFocus to invoke selection, will automatically be triggered by NVDA in both IE and Firefox when using the arrow keys to navigate page content.
Example 1: Tabs
<div role="tablist">
<div role="tab" tabindex="0" onfocus="alert('Switch content 1');"> Label One </div>
<div role="tab" tabindex="-1" onfocus="alert('Switch content 2');"> Label Two </div>
<div role="tab" tabindex="-1" onfocus="alert('Switch content 3');"> Label Three </div>
</div>
In JAWS, you can use the arrow keys to navigate between tabs and press Enter on the announced tab to activate it.
In NVDA however, using the arrow keys to announce each tab will automatically activate it.
Example 2: Implied form field labels
<input type="text" value="Street Address 1" onfocus="this.value=''" /><br /> <input type="text" value="Street Address 2" onfocus="this.value=''" /><br /> <input type="text" value="City" onfocus="this.value=''" /><br /> <input type="text" value="State" onfocus="this.value=''" />
In JAWS, setting focus to the Input field will cause the value to be cleared.
In NVDA however, using the arrow keys to navigate down the page will cause the form fields to be cleared.
Important: This method of form field labeling should never be used.
The events that are triggered for certain elements depend on the type of element that is being activated.
For example, adding an onClick handler to a natively active element such as an A tag with an Href attribute, or a BUTTON element, will be accessible for both mouse and keyboard users, regardless whether a screen reader is running or not.
However, if you do the same for a natively non-active element, such as a DIV or SPAN tag, it will not be accessible from the keyboard without a screen reader running.
Example 1: Standard link
<a href="#" onclick="alert('Clicked');" > Triggering Element </a>
This link is actionable from the keyboard with or without a screen reader running, and can be activated using the mouse.
Example 2: Simulated link with no onKeypress
<span role="link" tabindex="0" onclick="alert('Clicked');" > Triggering Element </span>
This simulated link is actionable from the mouse, and for screen reader users in Virtual Buffer Mode. However, it is not actionable for keyboard only users that have no screen reader running, nor is it actionable for screen reader users in Applications Mode.
Example 3: Simulated link with both onClick and onKeypress
<span role="link" tabindex="0" onkeypress="kpHandler(this, event);"
onclick="alert('Clicked');" > Triggering Element </span>
<script type="text/javascript">
function kpHandler(obj, ev){var k = ev.which || ev.keyCode; if (k == 13)alert('Pressed');}
</script>
This simulated link is actionable from the mouse and from the keyboard with or without a screen reader running.
However, the onKeypress is only activated for screen reader users in Applications Mode, and for keyboard only users,
and the onClick is only activated for mouse users, and for screen reader users in Virtual Buffer Mode.
Many accessibility issues arise when nesting active elements, which directly effects event propagation.
Example: Nested active elements
<div role="link" tabindex="0" onkeypress="kpHandler(this, event);"
onclick="alert('DIV clicked');" >
<img
alt="Triggering element"
src="icon.png"
onclick="alert('IMG clicked');"
/>
</div>
<script type="text/javascript">
function kpHandler(obj, ev){var k = ev.which || ev.keyCode; if (k == 13)alert('DIV pressed');}
</script>
This simulated image link performs different actions depending on the action mode (mouse or keyboard), and also depending on the browse mode for screen reader users.
It is, therefore, very important to ensure that nested active elements are not used to perform different actions.