Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(aria-hidden-focusable): disabled aria-hidden fieldset should not have focusable children #3056

Merged
merged 8 commits into from
Jul 15, 2021

Conversation

clottman
Copy link
Contributor

Closes issue: #2961

@clottman clottman requested a review from a team as a code owner June 30, 2021 22:12
straker
straker previously requested changes Jul 6, 2021
lib/commons/dom/focus-disabled.js Outdated Show resolved Hide resolved
straker
straker previously requested changes Jul 6, 2021
lib/commons/dom/focus-disabled.js Outdated Show resolved Hide resolved
straker
straker previously requested changes Jul 6, 2021
@@ -41,6 +41,50 @@ describe('focusable-disabled', function() {
assert.isTrue(actual);
});

it('returns true when content made unfocusable through disabled fieldset', function() {
var params = checkSetup(
'<fieldset disabled aria-hidden="true"><input id="target" /></fieldset>'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are technically running against the wrong node. The evaluate function should be run against the element that has the aria-hidden on it. Each of these tests (except for the shadow root one) runs against an input element. This can potentially cause problems later on if something about how we get tabbableElements stops returning the node itself.

@@ -14,6 +14,23 @@ function focusDisabled(el) {
return true;
}

let parentNode = vNode.parent;
while (parentNode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this more closely this will cause a pretty big performance problem. Since each child element of the aria-hidden element will use this function, each of them will walk up the entire parent tree of the page. If the aria-hidden is placed near the top of the tree, that is a lot of checking of nodes already checked.

We should cache on the VirtualNode information about this lookup so each element only needs to go up a few nodes until it finds an element that has already gone through this lookup chain.

We'll want to do something similar to is-hidden and cache the results of the recursive lookup onto each node we look at so we only ever have to look at a parent tree once.

Copy link
Contributor

@straker straker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache on focusDisabled isn't quite working. The cache won't break early from looking at the entire parent tree looking for a fieldset. What you'll need to do is look at at _isDisabled for every parent element and if it isn't undefined return the value. You'll also then want to cache that value on the node itself so a child of the node will only have to go up 1 parent to find the result.

And since this is specific to a fieldset parent being disabled, you'll probably want to name the variable _fieldsetDisabled or _fieldsetParentDisabled or something like.

let parentNode = vNode.parent;
const ancestors = [];
let fieldsetDisabled = false;
while (parentNode && !fieldsetDisabled) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we know we're not in the same shadow tree anymore we can stop looking at the parent tree completely as well. This also removes the need to check for this in the if statements as well.

Suggested change
while (parentNode && !fieldsetDisabled) {
while (parentNode && parentNode.shadowId === vNode.shadowId && !fieldsetDisabled) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we'll want to break once we know whether or not there is a parent fieldset disabled. Right now this only breaks if the value is true, but we want to short circuit the entire tree as soon as any node has the cached value regardless of what the value is.

@straker straker merged commit 0865bd7 into develop Jul 15, 2021
@straker straker deleted the 2961-fieldset-disabled branch July 15, 2021 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants