Technique FLASH17:Providing keyboard access to a Flash object and avoiding a keyboard trap
About this Technique
This technique is not referenced from any Understanding document.
This technique applies to content implemented in Adobe Flash.
Description
The objective of this technique is to allow keyboard focus to move to and from Flash content embedded in a web page. In browsers other than Internet Explorer, there is a problem related to keyboard accessibility of embedded Flash content. The problem is that, while both the Flash content and the HTML content around it may be keyboard accessible, many browsers do not support moving keyboard focus between the Flash content and HTML content without using a mouse. Once focus is placed inside the Flash content, a keyboard user will be trapped there. Similarly, when focus is placed somewhere else on the HTML content (outside the Flash content), it will be impossible to move focus into the content. This technique is designed to let the Flash author address this issue and provide support for moving focus between the Flash content and the HTML content via the keyboard.
This issue has been around for a long time, and is related to the way browsers implement embedded plug-ins. Until this problem is fixed, it is up to the Flash developer to come up with a work around. This technique is one of those workarounds. The approach behind this technique is the following:
- Two 'neighbor' focusable HTML objects are identified for each Flash content in the document (one before and one after the content). These elements can be any HTML elements that are part of the web page's tab order (such as links and form controls).
- The Flash content object itself is added to the document tab order as well, making it possible to tab into the content.
- Inside the Flash content, the Flash Player maintains its own tab order. Normally, when the start or end of the Flash tab order is reached (when tabbing through the content), focus will wrap to the beginning or end of the content's tab order, and it will not be possible to (shift) tab out of it. With this technique however, when a 'focus wrap' is detected focus will instead be moved to the neighboring element in the HTML tab order (allowing a keyboard user to 'break out' of the Flash tab order).
When the SWFFocus class is imported into a Flash project, the following will happen:
-
A JavaScript <script> tag will be generated and added to the HTML document containing the Flash content. This JavaScript code will:
- Set a tabIndex value of "0" on the <object> element of each Flash content found in the page. This causes the Flash objects to become part of the tab order.
- Optionally, create a hidden anchor element before and after the Flash content, which is used by the SWFFocus class to move focus out of the Flash content back into the HTML page. Alternatively, the developer can specify existing focusable HTML elements as adjacent tab stops for the Flash content.
- Set event handlers for the Flash content object, so that when it receives focus, the SWFFocus class is notified to manage the content's internal tab order.
- The SWFFocus class monitors changes in focus within the Flash content. When a focus wrap is detected in the content, a JavaScript function will be called to instead move focus back to the neighboring HTML content.
As indicated above, there are two ways in which this technique can be used:
-
Letting the SWFFocus class generate neighboring focusable elements in the HTML tab order for each Flash content (demonstrated in example 1 below)
By default, the SWFFocus class will create a hidden link element before and after an embedded Flash content. These elements are needed as 'anchor' to move focus to when (shift) tabbing out of the Flash content. This approach is the easiest to implement, as it does not require any additional work by the developer. The downside is that the hidden links will clutter the HTML tab order with meaningless elements (although these elements are only used as tab stops when tabbing _out of_ the Flash content, not when tabbing _into_ it). Because of this, it is recommended to use the following approach instead:
-
Explicitly identifying focusable HTML elements that come before and after the a Flash content in the HTML tab order (demonstrated in example 2 below)
With this approach, the developer can use ID values to identify the elements that come before and after the Flash content in the HTML tab order. This is done by setting special class names on the Flash content's <object> element. This is the preferred approach, as it does not cause an unnecessary cluttering of the tab order. However, it does require more work and awareness by the developer (who has to manually set ID values). Also, in some scenarios there simply may not be a next or previous focusable element for a Flash content.
Examples
The two examples below are shown in the working example of Preventing a keyboard trap in Flash content. The example html file has two Flash contents embedded in it. The first Flash content is embedded with the approach described in example 1. The second example is embedded with the approach described in example 2. The source of Preventing a keyboard trap in Flash content is available. The source zip file contains the SWFFocus class.
Note
To run the example from a local drive (as opposed to running it from a web server), the local directory needs to be added to Flash Player's security settings.
Example 1: Using automatically generated links
In this example, the SWFFocus class is used without explicitly identifying focusable HTML elements. This will cause SWFFocus to dynamically insert hidden links before and after the Flash content.
Loading the Flash Content
The Flash object in this example is added using SWFObject's dynamic publishing method, which means that the object tag is created dynamically by JavaScript in a way that the browser supports. While this is the recommended approach, it is not a requirement for using this technique. The SWFFocus class will also work when the object tag is hardcoded into the HTML document.
The sample code below shows how to load the content dynamically with SWFObject.
HTML and Javascript Code Sample for Example 1
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Keyboard Trap Fix Example</title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> <script src="swfobject_2_1.js" type="text/javascript"/> <script type="text/javascript"> var flashvars = {}; var params = {}; params.scale = "noscale"; var attributes = {}; attributes.id = "FlashSample1SWF"; attributes.name = "FlashSample1SWF"; swfobject.embedSWF("keyboard_trap_fix_custom_as3.swf", "flashSample1", \ "150", "200", "9.0.0", "expressInstall.swf", flashvars, params, attributes); </script> </head> <body> <p>The following Flash content automatically generates invisible links before and after the flash content, allowing keyboard focus to move out of the Flash content.</p> <div id="flashSample1"> <a href="http://www.adobe.com/go/getflashplayer"> <img alt="Get Adobe Flash player" src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" /> </a> </div> </body> </html>
Importing and Initializing the SWFFocus class in Flash
The SWFFocus class needs to be added to a Flash or Flex project's source path. The easiest way to achieve this is to import the SWFFocus.swc into Library path for your project or to copy the com/swffocus/SWFFocus.as file (including the nested directory structure) to the project's root directory.
When the SWFFocus class is added to the content's source path, it needs to be initialized with the following code:
import com.adobe.swffocus.SWFFocus; SWFFocus.init(stage);
The code for the class itself can be found in the source files.
Example 2: Explicitly identifying existing focusable html element
For a large part, this technique is the same as example 1 :
- The dynamic loading approach by SWFObject is used to load the Flash content
- The SWFFocus class needs to be added to the content's sourcepath and initialized in the Flash content
For more details about these steps, see example 1.
In this case however, special class names are added to the Flash content object. These class names indicate the ID values of the elements previous and next of the content in the HTML tab order. The class names are:
- 'swfPref-<previous ID>', where '<previous element>' should be the ID value of the previous element in the tab order.
- 'swfNext-<next ID>', where '<next element>' should be the ID value of the next element in the tab order.
For example, the HTML code could look like this (notice the added class names on the object tag):
<a href="http://www.lipsum.com/" id="focus1">test 1</a> <object class="swfPrev-focus1 swfNext-focus2" data="keyboard_trap_fix_as3.swf" tabindex="0" type="application/x-shockwave-flash"/> <a href="http://www.lipsum.com/" id="focus2">test 2</a>
Since this example uses SWFObject's dynamic loading, the class names will have to be specified as attribute when SWFObject is initialized. This is demonstrated in the code example below.
HTML and Javascript Code Sample for Example 2
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Keyboard Trap Fix Example </title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> <script src="swfobject_2_1.js" type="text/javascript"/> <script type="text/javascript"> var flashvars = {}; var params = {}; params.scale = "noscale"; var attributes = {}; attributes.id = "FlashSample2SWF"; attributes.name = "FlashSample2SWF"; attributes["class"] = "swfPrev-focus1 swfNext-focus2"; swfobject.embedSWF("keyboard_trap_fix_as3.swf", "flashSample1", "150", "200", "9.0.0", "expressInstall.swf", flashvars, params, attributes); </script> </head> <body> <a href="http://www.lipsum.com/" id="focus1">lorem</a> <p>The following Flash content uses existing links in the document to move focus to when (shift) tabbing out of the Flash content. The existing links are defined by placing special classnames on the Flash object.</p> <div id="flashSample2"> <a href="http://www.adobe.com/go/getflashplayer"> <img alt="Get Adobe Flash player" src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" /> </a> </div> <a href="http://www.lipsum.com/">lorem</a> </body> </html>
Note: this example assumes that the focusable HTML elements exist and have an ID value at the time SWFObject is called to insert the Flash content. However, in some situations it is also possible that these elements do not yet exist when the Flash content is created, or that the elements will be deleted dynamically at a later point. If this happens, it is possible to reassign ID values for previous and next focusable elements. To do this, call the SWFsetFocusIds() method on the Flash content object, like so:
var o = document.getElementById("FlashSample1SWF"); o.SWFsetFocusIds('prevId', 'nextId');
From that point on the updated IDs will be used to move focus to when tabbing out of the Flash content.
Related Resources
No endorsement implied.
Tests
Procedure
For a Flash content on a web page:
- If possible, confirm that the source of the Flash content imports and initializes the SWFFocus class
- Press the tab key to move through tabbable items on the page
- Confirm that it is possible to tab into the Flash content
- Continue tabbing and confirm that it is possible to tab out of the flash content
Expected Results
- Checks 3 and 4 are true