Problem/Motivation

In order to validate pages for W3C standards, we need to fix aria validation issues on collapsible fieldsets.
Right now, when fieldset is rendered with duplicated aria-expanded attribut without it's value.

Example taken from /admin/appearance page :

Line 161, Column 150: Duplicate attribute aria-expanded.
…min-theme" aria-expanded aria-expanded>Administration theme</summary><div clas…
Line 161, Column 150: Bad value for attribute aria-expanded on element summary.
…min-theme" aria-expanded aria-expanded>Administration theme</summary><div clas…

While according to aria document (http://www.w3.org/TR/html-aria/) it should be : aria-expanded="true" or aria-expanded="false", see: http://www.w3.org/TR/wai-aria-1.1/#aria-expanded

Proposed resolution

- Remove one aria-expanded
- Render the aria-expanded to true / false.

Remaining tasks

- Write failing test
- Remove one of the aria-expanded
- Render properly the aria-expanded

User interface changes

- none

API changes

- none

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because correct markup and aria is expected
Issue priority Normal because it does not break anything but screen-reader accessibility.
Unfrozen changes Unfrozen because it only changes markup and adds a JS file in the collapse library, but nothing disruptive.
Prioritized changes The main goal of this issue is accessibility and standarization of markup.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nod_’s picture

Issue tags: +JavaScript
Dom.’s picture

Issue tags: +js-novice, +Novice
drubb’s picture

Status: Active » Needs review
Issue tags: +drupaldevdays
FileSize
776 bytes

Here's a first patch for this

Dom.’s picture

Status: Needs review » Needs work

Hi,
Nice work : this solve the point to add open/close value depending on whether the attribut "open" is present at rendering time.
It nows needs further work to :
- toogle from open/close value depending on action (using JS)
- remove the duplicate of aria-expanded in source code

drubb’s picture

This second patch should fix the duplication issue, too. Regarding the JavaScript thing, I've no idea about the right place for the necessary additions. I had a look at collapse.js, but this file doesn't seem to be involved.

dimaro’s picture

Status: Needs work » Needs review

Check as Need review to run tests.

drubb’s picture

Status: Needs review » Needs work
Dom.’s picture

@drubb for #5: +1 for this ! The patch does not apply anymore but applying manually and testing it removes duplicate indeed. Let's find out the JS thing now and we will merge the three sub-patches to one then.

drubb’s picture

@dom patch #2 includes patch #1! Not sure if this is best practice?

drubb’s picture

Info for the JS part: the surrounding div has an attribute 'open'. It gets toggled even when js is disabled. If we find the place where this magic happens, we're almost done.

Dom.’s picture

Status: Needs work » Needs review
FileSize
1.44 KB

Here is a patch for the JS in collapse.js It actually works for Firefox for instance where Modernizr does do the job. On Chrome, it won't work because of :

if (Modernizr.details) {
   return;
}

Thus I would like @nod_ opinion on this :
- run the if(Modernizr...) after CollapsibleDetails runs, so that we can run setupSummary and have this.$legend accessible in the if(Modernizr)
- split toogle() method into two parts : what is about open that can be run by Modernizr, what is about arias
- call the aria part of toggle before the return statement in the if(Modernizr)

I guess that would make the trick. Would it be clean way however is up to @nod_.

drubb’s picture

Ah, that's why I didn't get it. I've used Chrome :-)

nod_’s picture

We need a separate js file for that, we can remove all the aria stuff from the fallback script and handle that for both native and polyfilled in a new file (that file can be added to the same library, just needs to be in a different file).

Dom.’s picture

OK, either me or @drubb that seems interested will try a proposal and we will come back for RTBC.
Thanks a lot for advice meanwhile !

drubb’s picture

@dom It's up to you, I have no idea about this modernizr stuff, sorry!

Dom.’s picture

Hum.. Could we have discussion on this ? Two questions :
- why adding arias in a new file for this, while it is not for other things ?
For instance arias are everywhere at : progress.js, states.js, tablegrad.js, basically every elements actually. Moving arias from collapse.js to aria.js for instance, we need to refactor everything to use the same aira file I guess, should not we ?
- in the case aria for collapse.js is in another folder. Does it need to be self-dependent, so also find the details elements and stuff or should it be called from the current js (thus injected), just like Modernizr is ?

nod_’s picture

Talked this through, Dom. is working on it.

Dom.’s picture

Assigned: Unassigned » Dom.
Status: Needs review » Needs work
Dom.’s picture

Status: Needs work » Needs review
FileSize
1.15 KB

Finally here is a final patch for the whole issue to be reviewed.

Dom.’s picture

Assigned: Dom. » Unassigned
nod_’s picture

Status: Needs review » Needs work

Missing the actual aria js file.

Dom.’s picture

Oh sh** ! Here it is !

Dom.’s picture

Status: Needs work » Needs review

The last submitted patch, 19: fieldset-aria-expanded--fix-2472177-19.patch, failed testing.

nod_’s picture

Status: Needs review » Needs work
  1. +++ b/core/misc/details-aria.js
    @@ -0,0 +1,16 @@
    +  Drupal.behaviors.detailsaria = {
    

    to make it easier to read I'd prefer detailsAria

  2. +++ b/core/misc/details-aria.js
    @@ -0,0 +1,16 @@
    +      $(context).find('details').on('click.details_aria', function(event) {
    

    This is missing the .once('detailsAria') after the find.

    I'd rather use event delegation on body, something like $('body').once('detailsAria').on('click.detailsAria', 'summary', function () {});

  3. +++ b/core/misc/details-aria.js
    @@ -0,0 +1,16 @@
    +        this.$summary = $(event.currentTarget).find('summary');
    

    Since listening to clicks on summary is more direct we can do something like var parent = event.currentTarget.parentNode;

    I don't think we need to add anything to this to make it work.

  4. +++ b/core/misc/details-aria.js
    @@ -0,0 +1,16 @@
    +        var isOpen = !!$(this).attr('open');
    

    On firefox this doesn't work so well, probably a event listener thing. Works fine in chrome.

Dom.’s picture

I have done all modifications but before link patch I still have something to resolve :
- chrome applies the open attribute after the JS. Thus when you have details close and you open it, open attribut is not yet there in the onClick method.
- firefox is polyfilled, and this polyfill happends before. Thus when you have details close and you open it, the open attribut is there yet on the onClick method.

Thus my isOpen value is reversed depending on Chrome or Firefox, and the behavior is then upside/down. Do you know how to order the JS in the assets ? Can I have the details-aria behavior running before the collapse.js polyfill so it could be the same behavior as per Chrome ? Maybe in .libraries.yml ?
I tried this but has no chances :

drupal.collapse:
  version: VERSION
  js:
    misc/details-aria.js: { weight: -10 }
    misc/collapse.js: { weight: -1 }
  dependencies:
    - core/jquery
    - core/modernizr
    - core/drupal
    - core/drupal.form
    - core/jquery.once
nod_’s picture

We really don't want to use weights. Thanks for finding out the root issue with FF/chrome. Feel free to upload the patch you have now even if it doesn't solve everything :)

I'll look into that last issue when I can.

Dom.’s picture

Status: Needs work » Needs review
FileSize
1.96 KB

Here is a patch that works for both Chrome and Firefox (without using weights). It add the corrections from #25 except does not make use of event.currentTarget but uses $(this) as per the exemple of on() in jQuery documentation.

nod_’s picture

We have eslint errors:

core/misc/details-aria.js
   9:10  error  Expected indentation of 10 characters  indent
   9:24  error  Expected '===' and instead saw '=='    eqeqeq
  12:22  error  Expected '===' and instead saw '=='    eqeqeq

✖ 3 problems (3 errors, 0 warnings)

About the code, I'd still like to use event delegation because of performance. On the module page (which has a lot of details element) we go from 6ms to 1ms for init.

Here is an updated patch. It solves the issue with firefox and chrome too. It's not really novice after all so I'm removing that :)

Status: Needs review » Needs work

The last submitted patch, 29: core-js-aria-details-2472177-29.patch, failed testing.

nod_’s picture

Status: Needs work » Needs review
FileSize
2.71 KB

better with the new file…

Dom.’s picture

Status: Needs review » Reviewed & tested by the community

Hi !
This is reviewed : I diffed it with #28 to understand the difference, tested with both Chrome and Firefox and finally check with W3C validator for the result.
RTBC+1 for me
If I could split hair, I would just add that the comment needs a full sentence with a point but that's okay !
// We're basing the value of

Dom.’s picture

Issue summary: View changes

Add beta-phase description.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/misc/details-aria.js
@@ -0,0 +1,28 @@
+        // We're basing the value of

Half a sentence

mgifford’s picture

Should it be this:

// We're basing the value of the open aria attribute.

I think that's what's happening. Thanks for catching the half sentence.

Cliff’s picture

Updating tags to indicate that this is a feature to improve accessibility and that the issue needs accessibility review.

nod_’s picture

Status: Needs work » Needs review
Issue tags: -Accessibility, -Needs accessibility review
FileSize
2.35 KB

Yup, sorry about that, fixed the comment.

Status: Needs review » Needs work

The last submitted patch, 37: core-js-aria-details-2472177-36.patch, failed testing.

nod_’s picture

FileSize
2.75 KB

Again, forgot the new file.

nod_’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 39: core-js-aria-details-2472177-37.patch, failed testing.

Status: Needs work » Needs review
mgifford’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Accessibility

I've tested this and it looks ready to be RTBC again. It's much more descriptive now.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/misc/details-aria.js
@@ -0,0 +1,28 @@
+        // The aria state is based on the 'open' attribute value of the parent.
+        function setAriaAttr() {
+          // It was open and we're closing it.
+          return $parent.attr('open') === 'open' ? 'false' : 'true';
+        }
+
+        $summary.attr('aria-expanded', setAriaAttr);
+        $summary.attr('aria-pressed', setAriaAttr);

It feels weird to call a function setAriaAttr() when in gets an attribute. Also we appear to call this method twice for little reason.

nod_’s picture

Status: Needs work » Needs review
FileSize
2.33 KB
1.79 KB

You're right, missed the big picture.

Dom.’s picture

Status: Needs review » Needs work

Hi !
In patch #45, aria-pressed correction have been forgotten (regarding patch #37). Thus, it does not validate W3C anymore. However alex.pott #44 has been corrected.

Dom.’s picture

Status: Needs work » Needs review
FileSize
2.54 KB
843 bytes

New patch with correction for aria-pressed added by compared to #45.

Status: Needs review » Needs work

The last submitted patch, 47: core-js-aria-details-2472177-47.patch, failed testing.

mgifford’s picture

Issue summary: View changes
FileSize
108.08 KB
91.98 KB

@Dom. you should get the same result with @nod_'s code as $variables['summary_attributes']['aria-pressed'] = $variables['summary_attributes']['aria-expanded']; and you're using the same logic in the line above. I think the patch in #45 would just be more efficient. The end result in both looks like this from what I can tell:

expanded screenshot

collapsed screenshot

Dom.’s picture

Status: Needs work » Reviewed & tested by the community

Hi!
Sorry, I retested patch #45 and it works fine actually !
@mgifford: indeed #45 is better, I just... don't know why I saw it wrong the first time.
@nod_: sorry for I did not tested properly #45 in the first place.

The reviewed patch is #45, not the following.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed the patch in #45. 98cddda and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed 98cddda on 8.0.x
    Issue #2472177 by Dom., nod_, drubb, mgifford: Collapsible fieldset have...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.