medialize / ally.js Goto Github PK
View Code? Open in Web Editor NEWJavaScript library to help modern web applications with accessibility concerns
Home Page: http://allyjs.io/
License: MIT License
JavaScript library to help modern web applications with accessibility concerns
Home Page: http://allyjs.io/
License: MIT License
the API documentation pages should be using prism.js for highlighted source code
>>>
, /deep/
and ::shadow
have been deprecated, see https://www.chromestatus.com/features/6750456638341120
We can traverse the DOM ourselves using Sizzle (probably overkill) or TreeWalker
:focus-within
is a state set on the element having :focus
and on all ancestor elements (piercing through ShadowDOM).
We can mimic that pseudo-class with the class .ally-focus-within
, which is added and removed upon document.activeElement
changing (determined by focus
event).
Internet Explorer 10-11 and MS Edge consider the <img>
element in the following snippet keyboard focusable ("tabbable") - no other browser does this.
<a href="http://example.org">
<img ismap src="…">
</a>
<!-- img remains keyboard focusable, a does not -->
<a href="http://example.org" tabindex="-1">
<img ismap src="…">
</a>
the API documentation pages need a way to integrate examples and interactive demos
The <canvas>
element may have children for compatibility. Those children, while not rendered, can be focused and tabbed to. But because they're not rendered, they do not necessarily have dimension and are thus considered hidden by dom/is-visible
.
Only Blink and WebKit understand tabindex
on SVGElements - detectable through element.tabIndex !== undefined
.
IE understands the focusable
attribute on SVGElement, where focusable="true"
behaves like tabindex="0"
and focusable="false"
renders the element inert. Not sure how to detect this yet.
add a getter to conveniently retrieve the <label>
elements for any given labelable elements
The intention of the namespace "focus" is not very clear. The behavior of the functions in this group is to maintain a certain behavior until that behavior is disengaged.
ally.js is being published under MIT license for the time being. Should the project ever achieve its goals (i.e. move into a FOSS foundation), it is likely that the license has to be changed a bit.
I wonder if it's wise to begin collecting signatures for a CLA (Contributor License Agreement) right away, rather than having to hunt them down later.
I also wonder if it is sufficient to make authors agree to the CLA (e.g. jQuery CLA) via a comment in the PR.
With Custom Elements on the rise and the specification itself promoting the use of WAI-ARIA it is even more important to make this stuff as simple as possible.
The <taco-button>
example illustrates how disabling a role="button"
is supposed to work: by removing tabindex
, onclick
, onkeypress
and adding aria-disabled="true"
- that is a lot of DOM action necessary to compensate for something otherwise as simple as <button … disabled>
.
It looks like form element semantics like [disabled]
and :disabled
will be available to Type Extensions (<input … is="my-cool-thing">
) only.
hook up gh-pages
with a proper domain (to escape the medialize.github.io domain).
see https://help.github.com/articles/setting-up-a-custom-domain-with-github-pages/
Issue with ally.query.tabsequence
While Blink and WebKit add <area>
elements to the tabbing sequence where they occur in the DOM, Firefox and IE do not. Gecko and Trident remove <area>
from the sequence and inject them (possibly multiple times) for every <img usemap>
referencing the <map>
those <area>
s are defined in.
Trident will redirect focus from <img usemap>
to the first <area>
of the referenced <map>
. Firefox does not do this. As this is undetectable behavior, differention in code would have to rely on platform.js (i.e. user agent sniffing).
This should not require refactoring util/sort-element-by-tabindex
, since the issue only exists with ally.query.tabsequence
.
Chromium 382901 and Gecko 840187 explain that a on page load [autofocus]
is executed, even when a fragment #foo
should make the page jump to an anchor in the document. The autofocus test confirms this.
A possible workaround could be to check the existence of :target
(fragment identifies an anchor) and temporarily remove all [autofocus]
attributes.
To provide an example how the various primitives are used in orchestration, a tutorial showing the mechanics of the <dialog>
element should be added to the docs: keyboard-accessible-dialog.md
When opening a modal dialog it is not enough to disable all the focusable elements, you also need to mark them "hidden" by way of aria-hidden="true"
. example
Marcy built that into angular dialog component and we should provide the same feature.
focus/trap
is trying to do as little intervention as possible - it only reacts to focus leaving the context.
Chrome's implementation of <dialog>
behaves similar to its implementation of ShadowDOM
in respect to positive tabindex values ([tabindex="1"]
) - i.e. they're treated as if they were local to the context (<dialog>
/ ShadowRoot).
To achieve the same effect in with focus/trap
we would have to intercept and handle all Tab and Shift Tab calls. We could not rely upon the browser picking the proper element to focus, because [tabindex="1"]
is considered globally (when not in a <dialog>
or ShadowRoot). We can use dom/query-tabsequence
to identify and properly sort a local tabbing sequence.
The question remaining is if listening for Tab and Shift Tab is sufficient. There may be browsers / OS / AT that have different ideas about this.
investigate how well Element.scrollIntoView() is supported, what WebKit's proprietary scrollIntoViewIfNeeded() (polyfill) brings to the table and how any of this can/should be used in scrollable lists. scrollIntoViewIfNeeded is likely not going to happen, but CSSOM View may have an answer.
scrollIntoView()
may cause scrolling even when the element in question already is in view. I assume that's why WebKit introduced scrollIntoViewIfNeeded()
. It may also move the entire page, instead of only the next scroll container
implement a simple interface for the "roving tabindex" approach to tabbable list items
Since only one focus-trap-handler can be active at any given time, we may want to offer an API that can stack these contexts. Trapping focus in context B while focus is already trapped in context A would remember the currently focused element of context A, abort trapping in context A, push context A onto a stack and activate trapping for context B. Upon deactivating the focus trap for context B, the trap for context A would be reactivated and the last foucsed element of context A would regain focus.
Gecko 409404 explains that the [focusable]
attribute is only implemented in IE9+ and is not part of SVG2. It is, however, defined in SVG-Tiny 1.2.
According to the Gecko issue, [focusable]
is necessary in IE.
make a11y.js compatible with CJS, AMD and global comsumption
while fixing mismatches in is/focusable, a few new focus-detection scripts have been added to supports. These need to be documented in docs/supports.md
Because ally.query.focusable
can find shadowed elements, util/sort-element-by-tabindex
must be extended.
tabindex
of an element within a ShadowRoot does not affect the global tabbing order, only the one within the ShadowRoot.[tabindex="1"]
within ShadowRoot - these elements are not added to the tabbing order.util/sort-element-by-tabindex
should sort the children of a ShadowRoot independently of the document. Within a document, the ShadowRoot must be treated as an immutable group.
user-modify, although dropped from CSS UI, is implemented in WebKit, Blink and Gecko. While -moz-user-modify
seems to do nothing, -webkit-user-modify
makes an element behave similar to [contenteditable]
and also makes it behave like [tabindex="0"]
was set.
I'm not sure how an element can be found by "having a certain style" other than filtering the CSSOM for appropriate selectors (and missing instances using element.style
). At this point a "known issue" seems like the way to go.
after building the project and the docs, the website needs to be published to the gh-pages branch.
KeyboardEvent.key may simplify handling keyboard events. But since it is only supported in Gecko and Trident, a Polyfill would be necessary.
There is a (very old) polyfill that may be the base for a new implementation. A trivial subset mapping was implemented for some SmartTVs.
This would make map/keycode
irrelevant.
the website needs some styles…
git clone [email protected]:medialize/ally.js.git
cd ally.js
git checkout master
npm install
npm run build-website
Will clone the repository, install the tools and generate the website to ally.js/web
.
Assets (like stylesheets, images, …) are maintained in ally.js/metalsmith/assets
.
because ally.js is not yet on cdnjs, we went ahead and pulled it off brcdn.org, which made us litter the following snippet all over the place:
<!-- FIXME: replace brcdn with cdnjs when ready -->
<script src="//brcdn.org/C1Jp8gmo8YhM1FQ8uuU78uKsA.js"></script>
<script>ally = ally.js;</script>
this needs to go before we can release the website and 1.0.0
using the technique "dynamic tabindex reallocation" [1] explored in https://jsbin.com/gumexa/10/edit?html,js,output it is possible to define the sequential navigation order constricted to groups of elements (rather than globally for the entire document).
[1] I suck at naming things
the demo works in Chrome, needs to be tested in other browsers. Do not forget about a[name] targets.
might be called observe/fragment
Hey! I'm the primary maintainer of a11y.js. I love what you're doing here, but curious why a separate project as opposed to working on one project? a11y.js
currently only does states, but that's because it was our primary need at the time. The goals of the two projects are the same, to make accessibility easier in a library independent way.
Why don't we combine forces and work together?
from 0.0.7 to 1.0.0 a lot of files have been moved around. to make sure old links don't break we should add redirection-pages (e.g. like this) during the npm build docs
or npm build website
phase.
extract element disabling into element/disabled
, so it is available outside of focus/disable as well.
the purpose of focus/disable remains to cover sub-tree querying and mutation montoring.
The name should be "disabled" as the survey confirms.
ally/element/disable
ally/element/disable
to properly disable form elementsally/element/disable
noting how to target in CSSally/is/disabled
to identify non-form elements disabled by ally/element/disable
some elements might not dispatch focus
event, so we need to observe document.activeElement
to be sure.
It does not make sense to disable the interactive components of a sub-tree without also marking the entire sub-tree as disabled. Therefore the module maintain/disabled
(formerly focus/disable
) should also engage and disengage aria-disabled
. A refactoring of get/ancestry-siblings
may be necessary to allow multiple context and filters.
var ancestrySiblings = getAncestrySiblings({
context: dialog,
});
ancestrySiblings.forEach(function(element) {
element.setAttribute('aria-disabled', 'true');
});
<html>
is focused in some browsers upon entering the document. But that doesn't mean a script can do the same.
<body>
is the default activeElement, which receives focus on document.activeElement.blur()
- but it can't be focused directly
selector/focusable
is using ::shadow
which only matches the first-level ShadowRoot. It should be using >>>
(formerly /deep/
, in Chrome still only /deep/
) instead.
While discussing ally with @darobin, it became clear that using modules (with systems like browserify) is not ideal yet. We're assuming two things:
the current structure is
node_modules/ally.js/
├── dist
│ ├── ally.min.js (UMD)
│ ├── ally.min.js.map (UMD)
│ ├── amd
│ │ └── <AMD files>
│ └── common
│ └── <CJS files>
└── src
└── <ES6 files>
the proposed structure is
node_modules/ally.js/
├── ally.min.js (UMD)
├── ally.min.js.map (UMD)
├── <CJS files>
├── amd
│ └── <AMD files>
└── src
└── <ES6 files>
which would allow the following - without any configuration - in CommonJS based systems:
// load ally.min.js UMD bundle
var bundle = require('ally.js');
// load the same structure as the UMD bundle, but from CommonJS modules
var bundleFromModules = require('ally.js/ally');
// load a specific module
var module = require('ally.js/query/focusable');
You can configure AMD to load the UMD:
require.config({
paths: {
'ally.js': 'node_modules/ally.js/ally.min',
}
});
// load ally.min.js UMD bundle
var bundle = require('ally.js');
OR you can configure AMD to load the modules:
require.config({
paths: {
'ally.js': 'node_modules/ally.js/amd',
}
});
// load the same structure as the UMD bundle, but from AMD modules
var bundleFromModules = require('ally.js/ally');
// load a specific module
var module = require('ally.js/query/focusable');
The same applies to es6-module-loader.
Firefox (and possibly other browsers) does not handle the loading of DataURIs (e.g. <img src="data:$uri">
) synchronously.
We can cheat this test by using UA-sniffing, or we can convert the currently synchronous supports infrastructure to allow asynchronous tests.
Internet Explorer 10-11 consider any scrollable container and its scrollable body focusable - no other browser does this.
<div style="width: 100px; height: 50px;">
<div style="width: 500px; height: 40px;">scrollable content</div>
</div>
To give a brief Twitter discussion a more formal home: jQuery UI implements tabbable and focusable as jQuery selectors. We've recently improved the implementation to deal with visibility:visible inside visibility:hidden elements, but there's still lots that we're missing (okay for jQuery UI's needs, so far).
To be able to replace our implementations, we would need to be able to import the relevant ally.js modules as an external dependency, then wrap them as jQuery selectors.
If we do that, we probably should also merge our tests, and remove the one's on jQuery UI's end: https://github.com/jquery/jquery-ui/blob/master/tests/unit/core/selector.js
/cc @scottgonzalez
In #23 @aFarkas points out that clicking on a <label>
, thereby forwarding the focus to the target element, does not maintain data-focus-source="click"
. We need to have a look at the focus redirection table and compensate accordingly. Note: This is only relevant to pointer interaction.
create dalek tests to verify library integrity across browsers
Evaluate JSDoc based tools to possibly move the API docs into the source files directly. This would make docs/api/**/*.md
irrelevant.
a few things have changed and with babel 6 -
http://jamesknelson.com/the-six-things-you-need-to-know-about-babel-6/
It is very common for widgets to be required to handle certain keys during their lifetime. According to ARIA Practices the dialog widget should handle Enter and Escape, next to Tab and Shift+Tab.
This is required for the "keyboard accessible dialog tutorial"
<svg tabindex="-1">
is still keyboard focusable (tabbable) in Internet Explorer and ally/element/disabled
does not work around that yet
In order to better understands what #24 needs to account / test for, we need a compatibility matrix for "element's forwarding focus" based on the browser/focusable test results.
Everything in tests/
needs to remain available at medialize.github.io/ally.js/tests/
.
But since we're not throwing node_modules
(formerly bower_components
) into gh-pages
anymore, we need to pull resources from somewhere else, e.g. cdnjs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.