Making Ember Applications’ UI Transitions Screen Reader Friendly.
When UI transitions happen in a SPA (or in any dynamic web application), there is visual feedback; however, for users of screen reading software, there is no spoken feedback by default. Traditionally, screen reading software automatically reads out the content of a web page during page load or page refresh. In single page applications, the UI transitions happen by rewriting the current page, rather than loading entirely new pages from a server; this makes it difficult for screen reading software users to be aware of UI changes (e.g., clicking on the navigation bar to load a new route).
If the corresponding HTML node of the dynamic content can be focused programmatically, screen reading software will start speaking the textual content of that node. Focusing the corresponding HTML node of the dynamic content can be considered guided focus management. Not only will it facilitate the announcement of the textual content of the focused HTML node, but it will also serve as a guided context switch. Any subsequent “tab” key press will focus the next focusable element within/after this context. However, keeping track of the HTML nodes to be focused can be tedious, repetitive, and error-prone since there could be hundreds of nodes that need to be programmatically focused in a SPA.
For ember applications, this addon solves the problem.
ember install ember-self-focused
Add the self-focused
component to all the desired templates/component corresponding to the routes.
{{#self-focused}}
<!-- html block to be yielded -->
{{/self-focused}}
Since the div will be focused, it will have a focus outline/highlight, if that is not desired, please add the following styles:
.self-focused:focus {
outline: none
}
self-focused
component on initial render invokes thedidInsertElement
and on re-render invokes thedidRenderElement
method of thefocus-manager
respectively passing the self HTML node as argument .focus-manager
service carries out the functionality of focusing the desired node.focus-manager
utilizes two state variables, namely_isFirstRender
and_nodeToBeFocused
.- initial value of the
_isFirstRender
is set totrue
- initial value of the
_nodeToBeFocused
is set tonull
- initial value of the
focus-manager
on initialization schedules_isFirstRender
to be set tofalse
in theafterRender
queue.focus-manager
has two private methods namely_setFocus
and_removeTabIndex
._setFocus
method- adds
tabindex=-1
to thenodeToBeFocused
- invokes native
focus()
method on it - attaches
_removeTabIndex
method to the_nodeToBeFocused
as theclick
andblur
event handler - sets
_nodeToBeFocused
tonull
- adds
_removeTabIndex
method, removes thetabindex
,click
andblur
event handlers fromnodeToBeFocused
focus-manager
service exposes two methods, namelydidInsertElement
anddidRenderElement
, which are consumed byself-focused
component.didInsertElement
anddidRenderElement
both accept a HTML node as an argument.didInsertElement
anddidRenderElement
both bail out if_isFirstRender
is true.- for
didInsertElement
the very lastself-focused
div passed to it for the render cycle wins - for
didRenderElement
the very firstself-focused
div passed todidInsertElement
for the render cycle wins, if and only if_nodeToBeFocused
was null when this method was invoked. didInsertElement
anddidRenderElement
both schedule the privatesetFocus
method, in theafterRender
queue after if_nodeToBeFocused
was updated.
ember test
– Runs the test suite on the current Ember versionember test --server
– Runs the test suite in "watch mode"ember try:each
– Runs the test suite against multiple Ember versions
ember serve
- Visit the dummy application at http://localhost:4200.
This project is licensed under the BSD-2-Clause License.