What's the proper way to handle programmatic focus of web components?
Calling focus() on a web component should focus the appropriate element in the shadow DOM. This means overwriting the focus method.
This is not enough though, because the web browser is not aware that the component is interactive. One consequence it that clicking an anchor pointing to the element will not focus it as it would a native interactive html element like <button>. There may be other implications that I'm not aware of.
The only way I know to make an element interactive is to give it a tabindex value. But tabindex="0" will create an extra tab stop, while tabindex="-1" will remove all tab stops inside the component. So neither works. My next step is to set tabindex="0", then switch the value on focus() and blur(). It seems crazy to me that I have to do all this hacky work for such a basic requirement (making a web component properly interactive and accessible). Am I missing something? Is there a better solution?
I was missing something indeed. Web components have a specific API for this: delegatesFocus. MDN docs.
When set to true:
calling focus() on the host element brings the first focusable element within the shadow DOM into focus.
so does clicking inside the component on any non focusable element
the tab sequence is unchanged
:focus styles on the host are applied
It's part of the web components specs so no worries about support.
Related
Is there a way to detect that a lockup loses focus when using TVML and TVMLKit JS on tvOS 12?
I know there's a highlight event when something receives focus using the following:
lockupElement.addEventListener("highlight", this.handleHighlight);
I want to handle when the lockup is no longer highlighted. The closest I've found to a solution is to add highlight-events to absolutely every other element and then reset any previously highlighted elements. This seems like a hack and it is also tedious and bug-prone adding it to every other element.
Anyone know of a better method?
If your lockup element is a custom element created through the extended interface creator you can override the didUpdateFocus(context, coordinator) function in your Swift class.
If it's just a default lockup I think you're out of luck.
I'm doing accessibility work and testing tab focus.
Is there an easy way skip focus to a specific element on chrome or any other browser? For example, there is a button in the middle of the page. How can I quickly focus that element without tabbing through everything before it first?
Just use the focus method in JavaScript:
document.getElementById('myButton') .focus();
The focus method exists on all elements that are naturally focusable (like buttons, links, form elements), or that have been made focusable with the tabindex attribute.
For input elements, you can also use the autofocus attribute to tell the browser to focus it as soon as the page is loaded.
Many websites use "skip links" for the ability to bypass lengthy navigation menus and quickly access the certain areas of the page. This is useful for end-users as well as developers who are testing webpages.
The basic principle is that you'll have invisible links at the very beginning of the page that use anchor elements and IDs (just like any in-page link).
For example:
<body>
Skip to main content
...
<main id="maincontent">
<h1>Heading</h1>
<p>This is the first paragraph</p>
WebAIM has a very good tutorial on this.
http://webaim.org/techniques/skipnav/
When you visit their site, press the TAB key before doing anything else, and you'll see an example of how this works.
I would consider this method to be more reliable than using JavaScript, as HTML is more widely supported.
Open chrome developper tools
Inside the console, you can focus any element using the following:
document.querySelector(selector).focus();
The selector can be obtained right clicking the element inside the code of the developer tools and selecting copy / copy selector
This does not required the element to have an id attribute, but you still can use it.
Chrome (and Firefox) both have really awesome tools for changing the current state of an element, e.g. setting it to a hover state so you can examine/modify css:
The problem is that this doesn't seem to set off any JavaScript events.
I'm currently trying to style a tooltip, which is shown on hover. It's difficult to hover over the element manually as the tooltip dissapears when I take the mouse off of said element, and setting the state to hover in the developer tools doesn't seem to set off the jQuery events.
I'm having to resort to adding an ID on the element in the developer tools inspector, then doing the following in the console:
$("#custom-element-hover").mouseover();
Which feels wrong (and is a little cumbersome).
Is there a better way to do this that I don't know about?
In a simple situation I think it is often easier to use the console as you are doing. But within developer tools, you can also find the event listener code and set a breakpoint on it:
You then right click on this handler and do view source, unminimize the source with the {} button and set a breakpoint in this handler function.
If this handler function triggers on unrelated events then you may need to right click on it and make the breakpoint conditional or add Watch Expressions to see when you are at the correct event.
You could also use the same method of breakpoint setting to instead skip over a particular mouseout event.
I can share with what I do in this kind of situations. I open elements tab in chrome debugger and right click on target element. Then I choose "Copy CSS path"
If you do this you will get something like this
#mdhelp-tabs > li:nth-child(1)
And this string can actually be used as legimit selector for jQuery. So this
$("#mdhelp-tabs > li:nth-child(1)")
will give jquery object with target element of dom in it.
So you would not have to assign an ID to every single element you want to deal with.
I am not sure but you can use console to handle tooltip
Currently I have a polymer element which contains a form with a few different fields. I have a tabindex setup on the input elements, however this polymer element is repeated 5 times throughout the page.
When I use tab for navigation, instead of following the tabindex within each component first, it instead goes to tabindex 1 for each component. Then all the tabindex 2's, and so forth. Is there any way for the tabindex to be encapsulated with/in the shadow dom?
You might want to see a '7.2 Focus Navigation' section in the Shadow DOM spec.
http://w3c.github.io/webcomponents/spec/shadow/#focus-navigation
Tabindex should be scoped in each node tree. Google Chrome already supports that.
I've implemented that. :)
If you find any unexpected behavior in the implementation, please file a bug for Chrome: http://crbug.com/
If you find an issue for the spec, please file a bug for the spec: Click a 'file a bug' button displayed at the top-right corner in the Shadow DOM spec.
Is there any way in HTML to tell the browser not to allow tab indexing on particular elements?
On my page though there is a sideshow which is rendered with jQuery, when you tab through that, you get a lot of tab presses before the tab control moves to the next visible link on the page as all the things being tabbed through are hidden to the user visually.
You can use tabindex="-1".
Only do this if you are certain it does not remove functionality for keyboard users.
The W3C HTML5 specification supports negative tabindex values:
If the value is a negative integer
The user agent must set the element's tabindex focus flag, but should not allow the element to be reached using sequential focus navigation.
Watch out though that this is a HTML5 feature and might not work with old browsers.
To be W3C HTML 4.01 standard (from 1999) compliant, tabindex would need to be positive.
Sample usage below in pure HTML.
Focusable
<a tabindex="-1" href="#" onclick="return false">Not focusable</a>
Focusable
Don't forget that, even though tabindex is all lowercase in the specs and in the HTML, in Javascript/the DOM that property is called tabIndex.
Don't lose your mind trying to figure out why your programmatically altered tab indices calling element.tabindex = -1 isn't working. Use element.tabIndex = -1.
If these are elements naturally in the tab order like buttons and anchors, removing them from the tab order with tabindex="-1" is kind of an accessibility smell. If they're providing duplicate functionality removing them from the tab order is ok, and consider adding aria-hidden="true" to these elements so assistive technologies will ignore them.
If you are working in a browser that doesn't support tabindex="-1", you may be able to get away with just giving the things that need to be skipped a really high tab index. For example tabindex="500" basically moves the object's tab order to the end of the page.
I did this for a long data entry form with a button thrown in the middle of it. It's not a button people click very often so I didn't want them to accidentally tab to it and press enter. disabled wouldn't work because it's a button.
The way to do this is by adding tabindex="-1". By adding this to a specific element, it becomes unreachable by the keyboard navigation. There is a great article here that will help you further understand tabindex.
Just add the attribute disabled to the element (or use jQuery to do it for you). Disabled prevents the input from being focused or selected at all.