Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add ARIA support (accessibility fix) #120

Open
wants to merge 3 commits into from

1 participant

@cheshrkat

Currently tooltips aren't vocalised by screen readers as they aren't associated in any way.

Added an option aria:true (default false) which...

  • sets tooltip role to tooltip
  • adds a generated ID to the tooltips
  • uses that ID to set aria-describedby

Dependency/assumption: the author must have set role application or document on a parent element for ARIA to work but that's beyond the scope that Tipsy can assert ARIA attributes. It seems appropriate to leave that to the author; noted the dependency in the docs.

Tested using Firefox 15 and NVDA.

Couldn't get the docs to build on my machine so I hope the formatting is ok.

Test file (drop in parent dir of tipsy clone):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=EDGE">
    <title>Page Title</title>
    <style>
    </style>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <script src="tipsy/src/javascripts/jquery.tipsy.js"></script>

    <link rel="stylesheet" type="text/css" href="tipsy/src/stylesheets/tipsy.css">
    <style type="text/css">
    body { padding: 2em; font-size: 14px; }
    a:after {
        content: " (aria-describedby:"attr(aria-describedby)")";
        color: black;
        speak: none;
    }
    .tipsy:after {
        content: "(role:"attr(role)") id: "attr(id);
        font-size: 14px;
        speak: none;
    }
    p { margin: 0 0 50px 0; }
    </style>

</head>
<body role="application">

<p>NB: role application or document must be set on parent for screen readers to vocalise this.</p>

<p><a class="ariatest" id="simple-tooltip" href="#" title="trigger describedby should match this id and you should hear this text in screen readers">tooltip</a></p>
<p><a class="ariatest" id="simple-tooltip2" href="#" title="trigger describedby should match this id and you should hear this text in screen readers">tooltip</a></p>
<p><a class="ariatest" id="simple-tooltip3" href="#" title="trigger describedby should match this id and you should hear this text in screen readers">tooltip</a></p>

<p><a class="ariafalse" id="simple-tooltip3" href="#" title="trigger describedby should be null and you will not hear this text in screen readers">tooltip aria false</a></p>


<script>
$(document).ready( function() {
    // needs a both option
    $(".ariatest").tipsy({trigger: "focus", aria: true});
    $(".ariatest").tipsy({trigger: "hover", aria: true});

    $(".ariafalse").tipsy({trigger: "focus", aria: false});
    $(".ariafalse").tipsy({trigger: "hover", aria: false});
});
</script>

</body>
</html>
@cheshrkat

Test page (place in parent of tipsy clone):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=EDGE">
    <title>Page Title</title>
    <style>
    </style>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <script src="tipsy/src/javascripts/jquery.tipsy.js"></script>

    <link rel="stylesheet" type="text/css" href="tipsy/src/stylesheets/tipsy.css">
    <style type="text/css">
    body { padding: 2em; text-align: center; font-size: 14px; }
    #simple-tooltip:after {
        content: " (aria-describedby:"attr(aria-describedby)")";
        color: black;
    }
    .tipsy:after {
        content: "(role:"attr(role)") id: "attr(id);
        font-size: 14px;
    }
    </style>

</head>
<body>


<p><a id="simple-tooltip" href="#" title="trigger describedby should match this id">tooltip</a></p>


<script>
$(document).ready( function() {
    $("#simple-tooltip").tipsy();
});
</script>

</body>
</html>
Ben Buchanan added some commits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 20, 2012
  1. Add basic ARIA support

    Ben Buchanan authored
Commits on Sep 24, 2012
  1. Made ARIA optional and attribute removed during hide as it is invalid…

    Ben Buchanan authored
    … once the tooltip is gone
  2. ARIA option documentation

    Ben Buchanan authored
This page is out of date. Refresh to see the latest.
Showing with 55 additions and 14 deletions.
  1. +25 −0 docs/src/index.html.erb
  2. +30 −14 src/javascripts/jquery.tipsy.js
View
25 docs/src/index.html.erb
@@ -294,12 +294,37 @@ an anchor tag's title attribute.</p>
<div class='code'><pre>&lt;script type=&#x27;text/javascript&#x27;&gt;
$(&#x27;a.live-tipsy&#x27;).tipsy({live: true});
&lt;/script&gt;</pre></div>
+
+ <!-- ARIA attribute Support -->
+
+ <h3>Support for ARIA attributes</h3>
+
+ <p>
+ ARIA attributes are supported using the option <code>{aria: true}</code>.
+ The tooltip trigger must have a parent set to <code>role=&quot;application&quot;</code> or <code>role=&quot;document&quot;</code> and the tooltip should be enabled on focus (screen reader users are most likely to be using the keyboard).
+ </p>
+ <p>
+ The tooltip will be set to <code>role=&quot;tooltip&quot;</code> and the trigger will be linked to the tooltip with <code>aria-describedby</code> (using a generated ID).
+ </p>
+
+ <p role='application'><a id='aria-example' href='#' title='You should hear this text in screen readers'>Tooltip with ARIA</a></p>
+
+ <div class='caption'>Aria example:</div>
+ <div class='code'><pre>$('#aria-example').tipsy({aria: true});</pre></div>
+
+ <script type='text/javascript'>
+ $(function() {
+ $("#aria-example").tipsy({trigger: "focus", aria: true});
+ $("#aria-example").tipsy({trigger: "hover", aria: true});
+ });
+ </script>
<!-- Options -->
<h2 id="options">Summary of Configuration Options</h2>
<p>Here is the default options declaration:
<div class='code'><pre>$.fn.tipsy.defaults = {
+ aria: false, // add ARIA attributes? (note dependencies)
className: null, // custom class to add to tooltip (string or function)
delayIn: 0, // delay before showing tooltip (ms)
delayOut: 0, // delay before hiding tooltip (ms)
View
44 src/javascripts/jquery.tipsy.js
@@ -15,6 +15,12 @@
}
return false;
};
+
+ var tipsyIDcounter = 0;
+ function tipsyID() {
+ var tipsyID = tipsyIDcounter++;
+ return "tipsyuid" + tipsyID;
+ };
function Tipsy(element, options) {
this.$element = $(element);
@@ -77,6 +83,12 @@
} else {
$tip.css({visibility: 'visible', opacity: this.options.opacity});
}
+
+ if (this.options.aria) {
+ var $tipID = tipsyID();
+ $tip.attr("id", $tipID);
+ this.$element.attr("aria-describedby", $tipID);
+ }
}
},
@@ -86,6 +98,9 @@
} else {
this.tip().remove();
}
+ if (this.options.aria) {
+ this.$element.removeAttr("aria-describedby");
+ }
},
fixTitle: function() {
@@ -110,7 +125,7 @@
tip: function() {
if (!this.$tip) {
- this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
+ this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>').attr("role","tooltip");
this.$tip.data('tipsy-pointee', this.$element[0]);
}
return this.$tip;
@@ -185,6 +200,7 @@
};
$.fn.tipsy.defaults = {
+ aria: false,
className: null,
delayIn: 0,
delayOut: 0,
@@ -240,19 +256,19 @@
* component.
*/
$.fn.tipsy.autoBounds = function(margin, prefer) {
- return function() {
- var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
- boundTop = $(document).scrollTop() + margin,
- boundLeft = $(document).scrollLeft() + margin,
- $this = $(this);
+ return function() {
+ var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
+ boundTop = $(document).scrollTop() + margin,
+ boundLeft = $(document).scrollLeft() + margin,
+ $this = $(this);
- if ($this.offset().top < boundTop) dir.ns = 'n';
- if ($this.offset().left < boundLeft) dir.ew = 'w';
- if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
- if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
+ if ($this.offset().top < boundTop) dir.ns = 'n';
+ if ($this.offset().left < boundLeft) dir.ew = 'w';
+ if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
+ if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
- return dir.ns + (dir.ew ? dir.ew : '');
- }
- };
+ return dir.ns + (dir.ew ? dir.ew : '');
+ }
+ };
-})(jQuery);
+})(jQuery);
Something went wrong with that request. Please try again.