12 Develop Accessible Oracle JET Apps
About Oracle JET and Accessibility
Oracle JET components have built-in accessibility support that conforms with the Web Content Accessibility Guidelines version 2.1 at the AA level (WCAG 2.1 AA), developed by the World Wide Web Consortium (W3C).
Accessibility involves making your app usable for people with disabilities such as low vision or blindness, deafness, or other physical limitations. This means, for example, creating apps that can be:
-
Used without a mouse (keyboard only).
-
Used with assistive technologies such as screen readers and screen magnifiers.
-
Used without reliance on sound, color, animation, or timing.
Oracle JET components provide support for:
-
Keyboard and touch navigation
Oracle JET components follow the Web Accessibility Initiative - Accessible Rich Internet Application (WAI-ARIA) Developing a Keyboard Interface guidelines. Follow these guidelines when using Oracle JET components in your app. For example, avoid setting
tabindex
to values greater than0
. The API documentation for each Oracle JET component lists its keyboard and touch end user information when applicable, including a few deviations from the WAI-ARIA guidelines. -
Zoom
Oracle JET supports browser zooming up to 400%. For example, on the Firefox browser, you can choose View -> Zoom -> Zoom In.
-
Screen reader
Oracle JET supports screen readers such as JAWS, Apple VoiceOver, and Google Talkbalk by generating content that complies with WAI-ARIA standards, and no special mode is needed.
-
Oracle JET component roles and names
Each Oracle JET component has an appropriate role, such as
button
,link
, and so on, and each component supports an associated name (label), if applicable. -
Sufficient color contrast
Oracle JET provides the Redwood theme, starting in Oracle JET release 9.0.0, which is designed to provide a luminosity contrast ratio of at least 4.5:1.
Oracle JET does not support the use of access keys due to their negative impact on assistive tooling and accessibility.
Oracle documents the degree of conformance of each product with the applicable accessibility standards using the Voluntary Product Accessibility Template (VPAT). You should review the appropriate VPAT for the version of Oracle JET that you are using for important information including known exceptions and defects, if any.
While Oracle JET is capable of rendering an app that conforms to WCAG 2.1 AA to the degree indicated by the VPAT, it is the responsibility of the app designer and developer to understand the applicable accessibility standards fully, use JET appropriately, and perform accessibility testing with disabled users and assistive technology.
About the Accessibility Features of Oracle JET Components
Oracle JET components are designed to generate content that conforms to the WCAG 2.1 AA standards. In most cases, you don't need to do anything to add accessibility to the Oracle JET component. However, there are some components where you may need to supply a label or other property.
For those components, the component's API documentation contains an Accessibility section that provides the information you need to ensure the component's accessibility.
Note:
Some Oracle products have run-time accessibility modes that render content optimized for certain types of users, such as users of screen readers. For the most part, Oracle JET renders all accessibility-related content all of the time. There is only a mode for users that rely on the operating system's high contrast mode, which is described in Create Accessible Oracle JET Pages.
Oracle JET components that provide keyboard and touch navigation list the keystroke and gesture end user information in their API documentation. Since the navigation is built into the component, you do not need to do anything to configure it.
You can access an individual Oracle JET component's accessibility features and requirements in the API Reference for Oracle® JavaScript Extension Toolkit (Oracle JET). Select the component you're interested in from the list on the left. You can also find the list of supported keystrokes and gestures for each Oracle JET component that supports keystrokes and gestures in the Oracle® JavaScript Extension Toolkit (JET) Keyboard and Touch Reference.
Create Accessible Oracle JET Pages
Content generated by Oracle JET is designed to conform to the WCAG 2.1 AA standards. However, many standards are not under the complete control of Oracle JET, such as overall UI consistency, the use of color, the quality of on-screen text and instructions, and so on.
A complete product development plan that addresses accessibility should include proper UI design, coding, and testing with an array of tools, assistive technology, and disabled users.
Note:
In most cases, end-user documentation for your app must describe information about accessibility, such as example keystrokes needed to operate certain components.
Configure WAI-ARIA Landmarks
WAI-ARIA landmarks provide navigational information to assistive technology users. Landmark roles identify the purpose of a page region and allow the user to navigate directly to a desired region. Without landmarks, assistive technology users must use the TAB key to navigate through a page.
The Oracle JET team recommends the use of WAI-ARIA landmarks to ensure page accessibility and provides examples you can use in the Oracle JET Starter Template collection. The following figure shows the run-time view of the Oracle JET Web Nav Drawer Starter Template. In this example, the page is organized into regions compatible with WAI-ARIA landmark regions, including regions for the banner
, navigation
, main
, and contentinfo
landmarks.
The highlighted code in the following example shows the landmarks for the Web Nav
Drawer Starter Template. Each landmark is placed on the HTML element that defines the landmark
region: div
for the navigation
regions,
header
for the banner
region, oj-module
for the main
region, and footer
for the
contentinfo
region.
<!DOCTYPE html> <html lang="en-us"> <head> <title>Oracle JET Starter Template - Web Nav Drawer</title> ...contents omitted </head> <body class="oj-web-applayout-body"> ...contents omitted <div id="globalBody" class="oj-offcanvas-outer-wrapper oj-offcanvas-page"> <div id="navDrawer" role="navigation" class="oj-contrast-marker oj-web-applayout-offcanvas oj-offcanvas-start"> <oj-navigation-list id="navDrawerList" data="[[navDataProvider]]" edge="start" item.renderer="[[KnockoutTemplateUtils.getRenderer('navTemplate', true)]]" on-click="[[toggleDrawer]]" selection="{{selection.path}}"> </oj-navigation-list> </div> <div id="pageContent" class="oj-web-applayout-page"> <header role="banner" class="oj-web-applayout-header"> <div class="oj-web-applayout-max-width oj-flex-bar oj-sm-align-items-center"> ...contents omitted </div> <div role="navigation" class="oj-web-applayout-max-width oj-web-applayout-navbar"> <oj-navigation-list id="navTabBar" class="oj-sm-only-hide oj-md-condense oj-md-justify-content-flex-end" data="[[navDataProvider]]" edge="top" item.renderer="[[KnockoutTemplateUtils.getRenderer('navTemplate', true)]]" selection="{{selection.path}}"> </oj-navigation-list> </div> </header> <oj-module role="main" class="oj-web-applayout-max-width oj-web-applayout-content" config="[[moduleAdapter.koObservableConfig]]"> </oj-module> <footer class="oj-web-applayout-footer" role="contentinfo"> ...contents omitted </footer> </div> </div> <!-- This injects script tags for the main javascript files --> <!-- injector:scripts --> <!-- endinjector --> </body> </html>
If your app includes a complementary region, add
role="complementary"
to the HTML div
element:
<div role="complementary"></div>
For additional information about WAI-ARIA landmark roles, see landmark_roles.
Configure High Contrast Mode
High contrast mode is for people who require a very high level of contrast in order to distinguish components on the page. Operating systems such as Microsoft Windows and macOS provide methods for users to run in high contrast mode.
The graphic below shows the effect of changing to high contrast mode on Oracle JET icon font images.
Oracle JET provides the oj-hicontrast
class that you can use to
configure high contrast mode in your app.
Understand Color and Background Image Limitations in High Contrast Mode
There are color and background image limitations in high contrast mode that your app may need to work around.
In high contrast mode the colors in the CSS may be ignored or overridden, including background, border, and text colors. Therefore, in high contrast mode you may need to find an alternative way to show state. For example, you might need to add or change the border to show that something is selected. Also, your app may need to show alternate high contrast images that work on dark or light background color. Some operating systems, like Microsoft Windows, offer multiple display profiles for high contrast mode, including a black-on-white and white-on-black mode.
Consider providing an image that includes a background, so either black on a white background or white on a black background. That way it won’t matter what the background color is on the page since the contrast is in the image itself.
Add High Contrast Mode to Your Oracle JET App
In most cases, you do not need to do anything to enable high contrast mode in your
Oracle JET app. If you're using RequireJS to load Oracle JET component modules, Oracle JET
loads a script that attempts to detect if a user is running in high contrast mode. If the
script succeeds at detection, it places the oj-hicontrast
class on the
body
element.
There is a limitation to this method, however. There is no standard way to detect
high contrast mode, and we can't guarantee that the script works in all cases on all browsers.
To guarantee that the .oj-hicontrast
styles are applied, add a user
preference setting for high contrast to your app and configure the app to add the
oj-hicontrast
class to the body
element when the
preference is set. When the class is added, the .oj-hicontrast
CSS styles are
applied to the page where defined. The code below shows an excerpt from the Redwood CSS which
changes the outline-width
to 3
on the
ojButton
component when the button has focus.
.oj-hicontrast .oj-button.oj-focus .oj-button-button { outline-width: 3px; }
Note:
For disabled content, JET supports an accessible luminosity contrast ratio, as specified in WCAG 2.1 - Success Criterion 1.4.3 Contrast (Minimum), in the themes that are accessible.
Section 1.4.3 says that text or images of text that are part of an inactive user interface component have no contrast requirement. Because disabled content may not meet the minimum contrast ratio required of enabled content, it cannot be used to convey meaningful information. For example, a checkbox may still appear checked in disabled mode, but since the colors may not pass contrast ratio, you cannot rely on all users being able to see that it's checked. If the information is needed to interact with the page correctly, you must convey it using a different method, for example as plain text.
Add High Contrast Images or Icon Fonts
To support high contrast image files, Oracle JET provides Sass mixins that you can use to generate the correct CSS in high contrast mode to:
-
Use an alternate image.
-
Use images without using background images.
The Oracle JET Cookbook provides examples that you can use at: CSS Images.
You can also use icon fonts instead of image files to support high contrast mode. The limitation is that icon fonts use a single color. Since these icons are text, they will be guaranteed to contrast against the background color on systems that ignore colors in the CSS. However, if you use color to show state (for example, changing an icon to blue when selected), the colors may be ignored in high contrast modes. You may need to find an alternative like setting a border instead. The Oracle JET cookbook provides icon font demos at: Icon Fonts.
Test High Contrast Mode
The recommended way to test high contrast mode in Oracle JET app is to set high contrast mode at the operating system level and test your app in browsers that support high contrast mode, such as Google Chrome, Microsoft Edge, and Mozilla Firefox.
For information about enabling high contrast mode, see the documentation for your computer’s operating system. For example, to turn high contrast mode on and off in Microsoft Windows, use the following key combination: Left Alt+Left Shift+PrtScn. You may need to refresh your browser to see the new mode.
Hide Screen Reader Content
Sometimes you want to have some text on the page that is read to the screen reader user, but the sighted user doesn't see. Oracle JET provides the oj-helper-hidden-accessible
class that you can use to hide content.
You can find the .oj-helper-hidden-accessible
style defaults in the
Redwood theme CSS file (web/css/redwood/x.x.x/web/redwood.css
).
For additional information about theming and Oracle JET, see Use CSS and Themes in Oracle JET Apps.
Use ARIA Live Region
An ARIA live region is a mechanism to notify assistive technologies when a web page content is updated.
When using a single page app, if there are any changes to the page or the page
region, the user of assistive technologies, such as screen readers, is not notified about the
changes in the page content since the URL of the app has not changed. To help provide a
notification to the screen readers when a page or segments of a page change, an ARIA live
region announces the dynamic changes within a web page. When the update takes place within an
ARIA live region, a screen reader is automatically notified, wherever its focus is at the
time, and it announces the updated content to the user. This can be achieved by using the
aria-live
attribute.
The aria-live
attribute identifies an element as a live region. It takes three possible values:
-
off
: No notification -
polite
: Screen reader notifies user once the current task is complete -
assertive
: Screen reader interrupts the current task to notify user
If the value of the aria-live
attribute defined for an element is set to polite
, your screen reader will not be interrupted and will announce the changes in the ARIA live region when the user has no activity on the screen. If the value is set to assertive
, the new information has high priority and should be notified or announced to the user immediately.
You can also use some of the advanced ARIA live region attributes to communicate information about the entire live region or a portion of the live region to assistive technologies. Some of the advanced live region attributes to use are:
-
aria-atomic
: Thearia-atomic
attribute is used along witharia-live
attribute when the page contains live regions. This attribute is used to set whether the assistive technologies should present the entire live region as a single unit or to only announce the regions that have been changed. The possible values aretrue
orfalse
. The default value isfalse
. -
aria-relevant
: This attribute is used in conjunction with thearia-live
attribute to describe the types of changes that have occurred within a given live region that should be announced to the user. The possible settings areadditions
,removals
,text
, andall
. The default setting isadditions text
.
The following example shows a sample of the ARIA live region defined in the
index.html
file of an app. In this example, the aria-live
attribute is set to assertive
and the aria-atomic
attribute
is set to true
:
<div id="globalBody" class="oj-offcanvas-outer-wrapper oj-offcanvas-page">
<!-- Region for announcing messages to Screen Readers -->
<div id="announce" class="sendOffScreen" :aria-live="[[manner() ? manner() : 'assertive']]" aria-atomic="true">
<p id="ariaLiveMessage"><oj-bind-text value="[[message]]"></oj-bind-text>
</div>
<div id="navDrawer" role="navigation" class="oj-contrast-marker oj-web-applayout-offcanvas oj-offcanvas-start">
<oj-navigation-list id="navDrawerList" data="[[navDataProvider]]" edge="start" item.renderer="[[KnockoutTemplateUtils.getRenderer('navTemplate', true)]]"
on-click="[[toggleDrawer]]" selection="{{selection.path}}">
</oj-navigation-list>
</div>
<div id="pageContent" class="oj-web-applayout-page">
... contents omitted
The following example shows how to set up the observables and event listeners in the
appController.js
file of the app.
define(['knockout', 'ojs/ojresponsiveutils', 'ojs/ojresponsiveknockoututils', 'ojs/ojcorerouter', 'ojs/ojarraydataprovider', 'ojs/ojknockout', 'ojs/ojoffcanvas'],
function (ko, ResponsiveUtils, ResponsiveKnockoutUtils, CoreRouter, ArrayDataProvider) {
function ControllerViewModel() {
var self = this;
self.manner = ko.observable('assertive');
self.message = ko.observable();
function announcementHandler(event) {
self.message(event.detail.message);
self.manner(event.detail.manner);
};
document.getElementById('globalBody').addEventListener('announce', announcementHandler, false);
var smQuery = ResponsiveUtils.getFrameworkQuery(ResponsiveUtils.FRAMEWORK_QUERY_KEY.SM_ONLY);
self.smScreen = ResponsiveKnockoutUtils.createMediaQueryObservable(smQuery);
var mdQuery = ResponsiveUtils.getFrameworkQuery(ResponsiveUtils.FRAMEWORK_QUERY_KEY.MD_UP);
self.mdScreen = ResponsiveKnockoutUtils.createMediaQueryObservable(mdQuery);
let navData = [
{ path: '', redirect: 'dashboard' },
{ path: 'dashboard', detail: { label: 'Dashboard', iconClass: 'oj-ux-ico-bar-chart' } },
{ path: 'incidents', detail: { label: 'Incidents', iconClass: 'oj-ux-ico-fire' } },
{ path: 'customers', detail: { label: 'Customers', iconClass: 'oj-ux-ico-contact-group' } },
{ path: 'about', detail: { label: 'About', iconClass: 'oj-ux-ico-information-s' } }
];
// Router setup
let router = new CoreRouter(navData, {
urlAdapter: new UrlParamAdapter()
});
router.sync();
this.moduleAdapter = new ModuleRouterAdapter(router);
this.selection = new KnockoutRouterAdapter(router);
// Setup the navDataProvider with the routes, excluding the first redirected
// route.
this.navDataProvider = new ArrayDataProvider(navData.slice(1), {keyAttributes: "path"});
... contents omitted
To send the announcement, you can use a dispatcher that can be defined within the page viewModel files or in the router enter method. The following example shows a page viewModel file that fires a dispatch in the self.transitionCompleted
lifecycle method.
define(['knockout','ojs/ojpopup'],
function (ko) {
function DashboardViewModel() {
var self = this;
self.transitionCompleted = function (info) {
var message = "Loaded Dashboard page"
var params = {
'bubbles': true,
'detail': { 'message': message, 'manner': 'assertive' }
};
document.getElementById('globalBody').dispatchEvent(new CustomEvent('announce', params));
};
For more information on using an ARIA live region, see ARIA Live Regions.