Summary

Access keys are a contentious area of accessibility, as they can sometimes clash with the shortcut keys used by user agents. One method to get around this problem is to allow users to define their own access keys. This post suggests a PHP class that allows users to define their own access keys.

Author: Gez Lemon

Contents

The AccessKey Class

Update: There is also an ASP version of this article.

Rich Pedley and I have been looking into ways of allowing users to define their own access keys. The AccessKey class allows users to define their own access keys. Access keys are a contentious area of accessibility, as the way they have been implemented in some user agents mean that they clash with the shortcut keys of the browser. The class provides various methods to help developers provide their own customisation form, along with methods to use them in their markup.

The file ak.zip contains the class and a sample file illustrating how to use the class.

I've set up a demonstration of the class in use. Any access key assignments will be enabled throughout the website. The following is an example of the markup to create the user-defined access key form.

<?php
require_once("ak.class.php");

$arBind = array("Home"=>array("/index.php", "1"),
            "Search Criteria"=>array("searchcriteria", "4"),
            "Quality Assurance"=>"/services.php",
            "Articles Archive"=>"/articles.php");

$objAK = new AccessKeys($arBind);

if ($_POST)
{
    if ($_POST["default"])
    {
        $objAK->useDefaults();
        header("Location: $PHP_SELF");
    }
    else if ($objAK->setCookies())
        header("Location: $PHP_SELF");
}
?>
<!DOCTYPE HTML PUBLIC 
    "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en-gb">
<head>
  <title>User-Defined Access Keys</title>
  <meta http-equiv="Content-Type"
        content="text/html; charset=ISO-8859-1">
</head>
<body>
<h1>User-Defined Access Keys</h1>
<?php
$objAK->displayOptions("accessnav");

if (!$objAK->isValid())
    echo $objAK->getErrors();
?>

<form id="accesskeysetup" action="ak.php" method="post">
<?php $objAK->generateForm(); ?>
<p>
<input type="submit" name="submit"
       value="Assign Accesskey Bindings">
<input type="submit" name="default"
       value="Assign Default Bindings">
</p>
</form>
</body>
</html>

Class Constructor

The constructor for the AccessKey class takes an optional array to help set up the class. The array may contain names and values, or names and an array that includes the value and a suggested access key, or a mixture of the two. The value may either be a URI, or an idref used with the label element. For example, the following defines an array of name value pairs (search contains an idref, intended to be used with a label):

$arBind = array("Home"=>"/index.php",
      "Skip Navigation"=>"#maincontent",
      "Search"=>"search",
      "Accessibility Statement"=>"/access.php");

$objAK = new AccessKeys($arBind);

The next example provides the value as an array that includes a suggested accesskey value.

$arBind = array("Home"=>array("/index.php", "1"),
     "Skip Navigation"=>array("#maincontent", "2"),
     "Search"=>array("search", "4"),
     "Accessibility Statement"=>array("/access.php", "0"));

$objAK = new AccessKeys($arBind);

The final example uses a mixture of name/value pairs, and a name with arrays that contain the suggested accesskey value.

$arBind = array("Home"=>array("/index.php", "1"),
     "Skip Navigation"=>array("#maincontent", "2"),
     "Search"=>array("search", "4"),
     "Quality Assurance"=>"/services.php",
     "Accessibility Statement"=>array("/access.php", "0"));

$objAK = new AccessKeys($arBind);

AccessKey Methods

The following lists the methods that can be used with the AccessKeys Class.

addAccessitem Method

The addAccessitem method allows a single item to be added to the collection of items that may be assigned an accesskey.

Examples

$objAK->addAccessitem("Meat", "meat.php");
$objAK->addAccessitem("Fish", array("fish.php", "9"));

removeAccessItem Method

The removeAccessitem method removes an item from the collection of items that may be assigned an accesskey.

Example

$objAK->removeAccessitem("Meat");

isValid Method

The isValid method returns a Boolean value indicating whether or not the values assigned were valid.

Example

if (!$objAK->isValid())
    echo $objAK->getErrors();

getErrors Method

The getErrors method returns a string containing errors from form submissions, or an empty string if there are no errors. The getErrors method should be used with the isValid method.

Example

if (!$objAK->isValid())
    echo $objAK->getErrors();

setCookies Method

The setCookies method returns a Boolean value indicating whether or not the values were valid accesskey values. If the values are inappropriate, isValid returns false, and getErrors can be used to retrieve the errors. Cookies must be set in the head of the document, and the current document must be reloaded before the values are effective. The return value from the setCookies method can be used to determine whether or not to reload the current page.

Example

if ($objAK->setCookies())
    header("Location: $PHP_SELF");

removeAllBindings Method

The removeAllBindings method removes all access keys defined for the collection.

Example

$objAK->removeAllBindings();

displayOptions Method

The displayOptions method displays a definition list where the definition terms are the names in the collection, and the definitions contain the assigned key, and suggested key if available.

Examples

Display options without specifying an id.

$objAK->displayOptions();

Display options with an id.

$objAK->displayOptions("someid");

generateForm Method

The generateForm method generates form sections based on the names provided in the collection. The method takes an optional value to indicate whether the generated markup is XHTML (by default, the value is false).

Examples

The following generates the form markup for HTML:

$objAK->generateForm();

The next example generates the form markup for XHTML:

$objAK->generateForm(true);

useDefaults Method

The useDefaults method assigns all of the values that have been suggested as default keys by the author, if any have been provided.

Example

$objAK->useDefaults();
header("Location: $PHP_SELF");

getAccessitem Method

The getAccessitem method returns the markup for a particular item, including the accesskey if one has been defined. If the item doesn't exist in the collection, the method returns an empty string. The accesskey can be ignored using the $bKey parameter, in which case, just the markup will be returned. As access keys may be assigned to links, labels, or form controls, an optional parameter allows the markup to return label tags. By default, the markup returns anchor tags.

Examples

An example of how this might be used in a navigation list

<ul id="navigation">
<li>
  <?php echo $objAK->getAccessitem("Home", true); ?>
</li>
<li>
  <?php echo $objAK->getAccessitem("Contact Us", true); ?>
</li>
</ul>

An example of how this might be used with a form element.

<?php echo $objAK->getAccessitem("Search", true, "label"); ?>
<input type="text" id="search" name="search" size="10">

The following retrieves a link without the access key assignment.

<?php echo $objAK->getAccessitem("Contact Us", false); ?>

Category: Accessibility.

Comments

  1. [user-defined-accesskeys.php#comment1]

    Very cool! Have you looked at classes in PHP 5? It has far better OO capabilities and allows the attributes to be defined as private or protected for true encapsulation.

    Posted by Doug on

  2. [user-defined-accesskeys.php#comment3]

    Could this technique be ported to classic asp? I know .net has classes but a classic asp version would be good.

    Posted by Tom K on

  3. [user-defined-accesskeys.php#comment4]

    Classic ASP supports the class construct. It doesn't support parameterised class constructors, but has a Class_Initialize event handler that can be used as a constructor without parameters, and also has a Class_Terminate event handler which acts as a class destructor, which isn't supported in PHP 4. ASP's class construct also supports private and public access to class members, so is more powerful in terms of encapsulation than PHP 4, but not as powerful as classes in PHP 5.

    I'll put together a basic version of this class in ASP, and post it later on.

    Posted by Gez on

  4. [user-defined-accesskeys.php#comment6]

    If I understand correctly, this only works with <a href="" accesskey=""> and <label for="" accesskey=""> elements (not the full set permitted to carry an accesskey attribute) and it does not allow for the presence of any attributes (class, title, ...) other than the ones listed?

    Posted by Jacques Distler on

  5. [user-defined-accesskeys.php#comment7]

    Hi Jacques,

    If I understand correctly, this only works with <a href="" accesskey=""> and <label for="" accesskey=""> elements (not the full set permitted to carry an accesskey attribute) and it does not allow for the presence of any attributes (class, title, ...) other than the ones listed?

    Yes, that's correct. Maybe a better approach would have been to amend existing markup with an identifier, in which case it would be applicable to all elements that are able to have an access key assigned with their original attributes in tact. The structure is all in place, and it wouldn't take much effort for someone to amend it to work that way.

    It would also be relatively simple to extend the class to include elements that can have an access key assigned that wouldn't necessarily have a label, such as a submit button. Similarly, the methods of the class could be extended to cater for attributes the author wants included. What's presented here is pretty basic, but as the functionality is encapsulated in a class, it's a straight forward process to extend it for more complex scenarios.

    Posted by Gez on

  6. [user-defined-accesskeys.php#comment8]

    Hi Gez,

    Was there a reason for you not using the DOM functions in PHP to perform this task?

    Posted by Gaz on

  7. [user-defined-accesskeys.php#comment9]

    Hi Gaz,

    I don't think the DOM functions would be appropriate in this case. PHP's DOM functions only work with XML (it would need to work with HTML as well as XHTML), are different between version 4 and 5 of PHP, and needs to be compiled into PHP, which isn't an option for people on a shared server.

    Posted by Gez on

Comments are closed for this entry.