Most of user interaction elements associated to a custom JavaScript behavior in Web applications can be HTML links (a elements) having a meaningful href attribute value, enabling them to be used in non JavaScript-enabled environments:
<a id="profile" href="profile">Profile</a>
<script>
document.getElementById("profile").onclick = function() {
return !open(this.href, "_blank", "scrollbars=no,status=no"); // whatever
};
</script>
But some interaction elements are deeply linked to JavaScript, either because the Web application they are contained in requires JavaScript to run or because they were generated by JavaScript and don't make any sense when it is not available.
For those, as I want users to be able to interact with them whatever device they are on (i.e. I don't want to define mouse, keyboard, touch, … interaction by myself on a span element), I see two relevant HTML elements: a and button.
My problem with the a element here is that it defines at least one behavior I don't want: the ability for the user to open its target anywhere he wants to (e.g. in a new tab), whereas the interaction I want to take place is specific to the current tab.
My problem with the button element here is that, as far as I can tell from the online resources, it is difficult to style reliably on all modern browsers (but I am not sure if it is still the case now).
Some of the facets of this question have already been answered elsewhere, but I can't find a comprehensive and up-to-date summary: what HTML element would you recommend to use?
If you want an element to semantically be a button without the style issues of a <button> element, or behavior of an <a href> element, then you should use an element with [role="button"]. <span> is commonly used, but pretty much any element could be used.
<span role="button"></span>
Now, [role="button"] is really just a flag for assistive technology, so some interactions need to be set up to react as a button, but they're actually quite easy.
Buttons (such as links and form elements) are typically tabbable. This isn't always necessary, such as if a keyboard shortcut has been set for it already. If you want the <span> in the tabbing order, just add the [tabindex] attribute:
<span role="button" tabindex="0"></span>
Now you can tab to the button, but you'd probably still want to trigger the click event when Enter and/or Space is pressed.
Simply adding an event listener to the button is enough.
For brevity this example uses jQuery:
$(document).on('keydown', 'span[role="button"]', function (e) {
if (e.which === 13 || e.which === 32) {
$(this).click();
e.preventDefault();
}
});
This uses an event delegation format to provide click support for all spans with [role="button"], you may want to choose a different selector depending on your situation.
Now all that's left is to listen for when the button is clicked:
Again, jQuery:
$('.myButtonClass').click(function () {
...do stuff...
});
Now, for other devices, you're going to want to trigger a click on, say, a touch event. If you're using jQuery, there are assorted libraries to support turning touch into click and/or tap. If you're not using jQuery, it's not a lot of work to listen for touch events.
I'm not going to provide a code example to handle touch, but that's because it depends on what the button is supposed to do. In some cases you want to trigger a handler simply by starting a touch on the button (equivalent to mousedown), in other cases you want to trigger the handler if you've started and stopped the touch event on the same element (similar to how click works normally).
Related
What event should I use in HTML/JavaScript to handle any "click" event that may happen on users platform, no mater what input method user uses?
HTML built-in elements like <button> or <a> handle any input method available to the use, including "clicking" links with Tab+Enter or with touchscreen. However if I use click event on any element that is not clickable by default (e.g. a <span tabindex="0">), then it's interpreted as mouse only.
I could in theory bind to one of the keyboard events too, but still some new input method may emerge in the future, so I'd prefer using something that would make the browser care about what input devices it handles, not the website. I'm also not sure about the touchscreens.
I am trying to add more accessibility to my app so i've added eslint-plugin-jsx-a11y to my eslint process. This has been great, however I have a question in regards to the click-events-have-key-events rule (https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md ).
I want to add an onKeyDown or an onKeyPress anywhere I'm using the onClick in my react code. However I am not sure which keycode I should be listening to.
If, for example, I just do
<div
onClick={this.myFunction}
onKeyDown={this.myFunction}
/>
That onKeyDown function fires when i just tab away from that div. So I am thinking I need to filter keyCodes, however when trying to meed accessibility standards, I'm not sure which keyCodes I need to listen for. Is the enter keyCodes enough - do all screen readers respect this for example?
Looking for some insight into this to help make my app more accessible and screen reader friendly.
You didn't ask specifically about this but the best solution is to use a native html element if possible. See the first rule of ARIA use. Native elements have the behavior built in to the element and work great with screen readers.
However, sometimes you need to create a custom element and that's where ARIA comes in. But you need both attributes and a role to make a custom element, and additionally you need keyboard/mouse handlers if the element will be interactive.
The types of keyboard events you listen for depends on the role. For example, if you were creating your own link element, instead of using an <a>, you'd listen for the ENTER key. If you were creating your own button, you'd listen for both the ENTER and SPACE keys.
The types of keys you listen for are explained in the design patterns in "WAI-ARIA Authoring Practices 1.1". For example, see the "Keyboard Interaction" section for buttons.
The ensure all elements are clickable using the Enter key, I'm using the following method:
document.addEventListener('keydown', function(e){
if( e.keyCode === 13 ) {
e.target.click();
}
});
And for most clicks, it works really well. The problem is with elements that don't have a click event bound directly, but are clickable through bubbling up. For example:
jQuery(document).on('click', function(e){
jQuery(e.target).addClass('active');
});
Clickable elements that are bound this way, will not be triggered using the first example. I've found out that NVDA, somehow, literally makes all elements clickable using the keyboard, whatever the method used to bind them. If NVDA is turned on, elements that are bound just like in example number 2 will be triggered.
I'd like to understand how NVDA does this (or if you have another idea to approach this) so I can copy that behavior to my application, that is being used by people with motor impairments and have to use the keyboard solely, without screen readers.
The solution has to be pure JS or jQuery.
It is really great that you're interested in making your site accessible, it is very much appreciated.
But please, don't do such things, they yield unpredictable screen reader behavior and often upset the accessibility tree itself.
Rather than making all elements clickable, just think about what result you need to achieve. If you want your links and buttons to be usable with a screen reader, you have to do nothing, it's already implemented in HTML - boom, no Javascript, no jQuery, pure HTML.
If for some reason you want your divs act like buttons and spans act like links, just use ARIA roles:
<div id="myDiv" role="button">Click me!</div>
I'm a link to <span id="linkToGoogle" role="link">Google</span>, isn't that nice?
Again - boom, no Javascript, no jQuery, pure HTML.
However, if you can and where you can, just use semantical HTML elements, not ARIA roles: <button> for buttons, <a href...> for links and so on. I could elaborate more if I knew what specifically you want to make clickable.
I have containers with multiple lines but only the first one visible (overflow:hidden). The container is expandable upon a click. (See https://stackoverflow.com/a/6972830 and the jsFiddle http://jsfiddle.net/JUtcX/2/)
If someone performs a Ctrl+F with text from the non-visible lines, the browser reports a match but cannot show it (because it's hidden).
How can I react to Ctrl+F and open the container whether a non-visible text in it was searched for?
[Update]
Approaches that do not meet all requirements:
Listening for Ctrl+F.
I have multiple containers and only want to expand those containing the search phrase. Upon listening for Ctrl+F I could only open all containers at once.
Does not work on all systems. This is a negligible defect only, though.
Chrome-specific workaround (link)
At least also Firefox should be supported
You can do something like this:
function find(e) {
if (e.ctrlKey && e.keyCode == 70) {
document.getElementById("hide").style.display = "block";
}
}
document.addEventListener('keyup', find, false);
#hide{
display: none;
}
<div>
ASDF:
<div id="hide">
Hidden
</div>
</div>
Listening to browser Ctrl+F/find layout modifications
I don't think it is possible to listen to those layout modifications.
When the browser find an element, it is equivalent to call
scrollIntoView for the matched element. Thus a scroll event will be
fired only if the container div is scrollable.
In the example, the parent style is overflow: hidden;. Thus it does
not trigger any scroll event.
It becomes then impossible to listen to these layout change, because
the only workaround that exist to listen to scroll event on
overflow:hiden element, is to listen to mouse wheel event ...
The bad story is that it is then impossible to prevent user from
modifying layout through the browser find, because even if one can
prevent Ctrl+F or F3, we can't prevent user from using the Edit-> Find
menu in Firefox or IE
JBE
Listen for Events from Browser "Find" Window in JavaScript
I don't know of any way you can listen for a find-like event and if
that's supported in any browser it sure isn't a portable solution.
I also don't know what you're trying to achieve but I think that your
best option is to listen for the keyboard events that trigger the find
window and attempt to cancel them while attempting to emulate the
find-toolbar/window with JavaScript of your own. This is however a
herculean (and nearly impossible) task due to some browsers
customization of keyboard shortcuts depending on the localization (for
instance, in IE, en-US uses Ctrl+F (for Find) while pt-PT uses Ctrl+L
(for Localizar, meaning find)).
Conclusion: I think you're out of luck there...
Miguel Ventura
Searching for text (Ctrl+F) across hidden spans
Chrome search feature (ctrl+f) finds hidden text ( but it's invisible! )
I'd like to detect if a drop down is expanded or not. I don't want to use extra event handlers for click/mouseover etc because the drop-downs are dynamic and for other reasons I can't use something like jQuery live. Basically I'd like something that can given an arbitrary select element (no other attached event handlers, classes, etc), can give a true/false answer on whether it is expanded or not.
For my specific application, I am handling mouse wheel events, but don't want to handle them when a drop down is open (which would override the browser default functionality). However, I still want to handle the mouse wheel events when the mouse has hovered over the select, but has not opened it.
I looked into this before, for similar reasons. I could never find a solution other than trying to track it manually which really doesn't work. There are several ways to open/close a select (drop down) such as Alt+Dn Arrow. An open select will close if the user clicks on something outside the browser. Trying to keep track of the state of the select is an exercise in futility. Unless someone else comes along with something I missed on my hunt, you'll have to code around it as elegantly as you can.
How about when it's got focus, even if it isn't expanded? You specifically ask for expanded because you don't want to override default browser behaviour, but the browser behaviour should be to scroll through the items when the item is focussed, even if it isn't expanded, so I would say you'd be better off detecting focus.
If you're okay with that, then you can certainly easily detect when a field has focus and when it loses it, by using the JQuery focus() and blur() methods, or focusin() and focusout().
http://api.jquery.com/focus/ and http://api.jquery.com/blur/
http://api.jquery.com/focusin/ and http://api.jquery.com/focusout/
Hope that helps.
Maybe you could do something like this:
$('#dropdown').live('click', function(){
//bind mousewheel here
});
$('#dropdown').live('change', function(){
//unbind mousewheel here
})