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.
Related
For accessibility I'm attempting to allow arrow keys to control the camera orbit of my model viewer the moment the poster is dismissed. So far it seems that I'm able to control the camera with the arrow keys, but only if I interact with the model-viewer a second time (i.e. I click to dismiss the poster, then can't manipulate the camera until I click the 3D model at least once). This is bad form for accessibility.
Is there a way to force model viewer to accept keyboard input without needing to click/touch the 3D model at least once? So far I've tried:
Using the focus(); function on my model-viewer element, on my .userInput div within it, and the canvas element within that
Setting the tab indexes of each of these to 1 with no success
Using delegateFocus on my elements
Using the enableInteraction(); function native to model-viewer
Adding an event listener when the poster is dismissed, via this.addEventListener('keydown', this[$modelViewer].value?.onKeyDown);
I've verified that these elements are being manipulated/appended in the correct way, so it appears using focus and tab indexes isn't what allows model-viewer to take keyboard input in the first place.
How can I force model-viewer to accept keyboard input the moment the poster is dismissed and the 3D model is loaded?
You should be able to call .focus() on your .userInput div, the tricky thing is that <model-viewer> creates a Shadow DOM. The purpose of a shadow DOM is to encapsulate its child components, so you can't just get the element by class as you would in a regular DOM.
Instead, I had to first access the shadowRoot, then look for the right <div> inside. For example, I was able to use this on https://modelviewer.dev/, it focuses the .userInput div whenever you click anywhere on the outer document. It uses some selection trickery that you might need to modify for your own use case:
window.addEventListener("click", (evt) => {
console.log("Focusing...");
document.getElementsByTagName("model-viewer")[0].shadowRoot.children[1].getElementsByClassName("userInput")[0].focus();
});
I presume since you have full control of your <model-viewer>, you might be able to use this focusing approach on the load event.
Update:
I just read that you want to give it keyboard focus upon clicking to dismiss the poster, so you might be able to use that "click" event instead of the load event.
I'm trying to simulate an actual tab key press in JavaScript. I don't want to focus on the next element or anything like that, I just want to make it seem like the tab key has been pressed.
The reason why is because I am building a form JavaScript class where I want to be able to use the enter key just like tab. If someone is using a native BROWSER autocomplete, I need to fire the tab key to capture the selected autocomplete response. If I just move to the next input it won't capture their autocomplete selection and leave the field blank.
Any thoughts?
I don't think it's possible; an article about DOM events here ...mentions that firing an event doesn't trigger the default result of the user action, for security reasons; the script should not be able to simulate user interaction directly. You will have to simulate the behavior the keypress causes (such as focus on a field), instead of trying to actually simulate a keypress. You probably won't be able to interact with the browser's native autocomplete functionality, unless the browser explicitly provides a means for you to do so.
Edit:
See also: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autocomplete] (Autocomplete HTML attribute)
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.
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).
One of the most recommended ways to listen for a change of a input text field is to bind that field to a key up event. That works fine in most cases. But there are cases where this is not working. In Firefox for example one has the option, when text is already selected, to delete it by using the context menu. And this doesn't fire a key up event. I haven't found any event that is fired for that text field when doing this.
Any suggestions how I can react on this (in pure Javascript or jQuery)?
See the oninput event, and my write up about it here.
oninput fires for all forms of text input - including cut, paste, undo, redo, clear, drag and drop and spelling corrections. It's a HTML 5 event which isn't supported in Internet Explorer 8 and lower (but it is in the latest IE 9 preview). However, Internet Explorer supports a proprietary event on all DOM objects - onpropertychange. This fires whenever the value of an input element changes.
I didn't notice you'd tagged with jquery — since you did, it's probably worth mentioning that I wrote a plugin to implement the oninput event cross browser. You can find it here.
The best way is to store the value on a focus event and recheck the value on a blur event. Listening to key events fires a lot of usually redundant processes. Most of the time, you are only interrested in a field value when the user is done inputting (or deleting) it.
This works cross browser, though delegating focus/blur can be an issue in some browsers. The easiest way is to apply blur/focus listeners to the element directly.
Only exceptions are implementations like autosuggest/complete and even then you might want to debounce key input so it only fires when the user idles for a few hundred miliseconds.