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

RFC - Upcoming a11y design #293

Closed
8 of 18 tasks
cibernox opened this issue Feb 6, 2016 · 24 comments
Closed
8 of 18 tasks

RFC - Upcoming a11y design #293

cibernox opened this issue Feb 6, 2016 · 24 comments

Comments

@cibernox
Copy link
Owner

cibernox commented Feb 6, 2016

After some comments in other issues, I've decided to gather together all the a11y design and best practices.

I've also found this example to be particularly enlightening.

NOTE: The image deliberately omit the roles of the options of the list because seems to be a consensus that are role=option aria-selected=true/false aria-current=true/false aria-disabled=true/false. This focuses on what wires the trigger, the searbox and the list of options together only.

Starting with the most basic component, Ember Basic Dropdown, the a11y is relatively simple.

basic-dropdown-a11y

On top of this we build the power-select and power-select-multiple

single-select-a11y

multiple-select-a11y

I'm also omitting aria-description, aria-label.

cc @jmacqueen @martndemus

In case this is the path taken:

  • The options list has role=listbox.
  • Groups have role=group
  • Each option has role=option.
  • The selected option has aria-selected=true.
  • The highlighted option has aria-current=true.
  • The disabled options has aria-disabled=true.
  • Searchbox of the single component has role=combobox.
  • Searchbox of the single select has aria-expanded=true, aria-owns=id-of-the-listbox and aria-autocomplete=list.
  • Searchbox of the multiple select has aria-expanded=true, aria-owns=id-of-the-listbox and aria-autocomplete=list. aria-expanded has to be false/true depending on if the options are visible?
  • Trigger has role=button
  • Trigger aria-owns=<id-of-dropdown>
  • Trigger has aria-pressed=true/false. Should we remove aria-expanded then?
  • Trigger get aria-disabled=true when passed disabled=true to the component.
  • Trigger has aria-haspopup=true.
  • Accepts aria-labelledby (applies to the trigger).
  • Accepts aria-describedby (applies to the trigger)
  • Accepts aria-requited (applies to the trigger)
  • Accepts aria-invalid (applies to the trigger)
@cibernox
Copy link
Owner Author

cibernox commented Feb 6, 2016

The main point of this design for me is that is consistent.
There is the button + dropdown responsibility, owned by ember-basic-dropdown, and then there is the combobox + listbox responsibility that lives in Ember Power Select. They are 2 reparate concerns.

@jmacqueen
Copy link
Contributor

I think we're working really hard to pound a square peg into a round hole.

aria-autocomplete and combobox semantics are very specific. They expect that the ultimate result will reside in whatever element is flagged as a combobox and aria-autocomplete=list also requires the use of aria-activedescendant.

That's not where the search results live here, which is why I was suggesting in the other thread that we dispense with role=combobox all together and leverage aria-controls instead. Ultimately, I think it will be a simpler way to get something validly accessible. By my reading, what you have here is going to be so hard to represent as a combobox that you might as well skip it and just lay out the controlling relationships between the pieces.

@jmacqueen
Copy link
Contributor

I think the dropdown semantics are pretty well understood (my awkward attempt to diagram follows)
dropdown aria 001

Trigger

  • role=button
  • aria-haspopup=true tells AT to treat the trigger as a host for conditional content
  • aria-expanded=true/false tells AT that conditional content is expanded
  • aria-pressed=true/false tells AT that the button is in a pressed or 'true' state (technically different from whether the conditional content is expanded, but in practice usually the same).
  • aria-controls=<id of dropdown> is all we need since there is no requirement that the trigger element own or have a direct DOM relationship to the dropdown

@cibernox
Copy link
Owner Author

cibernox commented Feb 8, 2016

@jmacqueen Yes, on the dropdown I think the looks ok.
Should se use aria-owns or aria-controls (or both)?

@jmacqueen
Copy link
Contributor

I prematurely sent the earlier post. It's updated now. But the answer is aria-controls is all you need.

More amazing diagrams to follow.

@jmacqueen
Copy link
Contributor

Single Select key points

screen shot 2016-02-08 at 10 40 17 am

Search

  • <input type=search>
  • aria-controls=<id of listbox>

Listbox

  • role=listbox
  • aria-controls=<id of trigger> since the trigger will hold the content changed from the listbox

Options

All the usual option stuff

@jmacqueen
Copy link
Contributor

I'm looking at the multiple select now. I have a little time before I get pulled into more actual work 😄

@ZoeBijl
Copy link

ZoeBijl commented Feb 8, 2016

Please see the Authoring Practices Guide's section on autocomplete for more information about keyboard handling.

ps. there is a discussions going on at the moment regarding combobox:

ACTION-1490 proposal says good bye to the "inline" notion for combobox

@jmacqueen
Copy link
Contributor

Multi-select key points

First pass

screen shot 2016-02-08 at 1 38 34 pm

In the trigger

  • Search Box
    • <input type="search">
    • aria-controls=<id of listbox>
    • needs to be in the tab order
  • List of selections role=list (this is different from listbox in that the individual items are not expected to be directly clickable). <ul> has an implicit role=list
    • Selection with role=listitem. <li> has an implicit role=listitem
      • Close Button with role=button or preferably an actual <button>
        • aria-label=something useful
        • tabindex=0 to allow each close button to receive focus

In the dropdown

  • Listbox
    • Basically the same as single select, but ideally, aria-controls=<id of selection list>

cibernox added a commit to cibernox/ember-basic-dropdown that referenced this issue Feb 10, 2016
See cibernox/ember-power-select#293 (comment)

 - [x] `role=button`
 - [x] `aria-haspopup=true` tells AT to treat the trigger as a host for conditional content
 - [x] `aria-expanded=true/false` tells AT that conditional content is expanded
 - [x] `aria-pressed=true/false` tells AT that the `button` is in a pressed or 'true' state (technically different from whether the conditional content is expanded, but in practice usually the same).
 - [x] `aria-controls=<id of dropdown>` is all we need since there is no requirement that the trigger element own or have a direct DOM relationship to the dropdown
@cibernox
Copy link
Owner Author

@jmacqueen I've implemented all tasks but two:

  • tabindex=0 to remove buttons. I will need some more work
  • Search Box: include close button < -- I don't actually understand this

@miguelcobain
Copy link
Collaborator

@cibernox I see the value in using aria attributes for styling. However, css attribute selectors are known to perform badly in IE browsers. I'm not saying this by my own experience, unfortunately.

I've seen that angular material recently changed their layout styles to use class selectors instead of attribute selectors. See https://material.angularjs.org/latest/layout/introduction in the section "under-the-hood".
Angular Material is targeted for all browsers with versions n-1; where n is the current browser version, so I assume this was a real problem they've faced?

@jmacqueen
Copy link
Contributor

@cibernox "Search Box: include close button" means that the search box in use in multi-select also has its own close button and it would have the same structure as the close button in each of the selections. Sorry that was unclear.

@miguelcobain From my reading (insert first thing that Google put up here as an example), I haven't seen any benchmarking of attribute selectors that shows an appreciable difference in performance unless you have well over 20,000 elements on the page. This, coupled with the WCAG recommendation to style against the WAI-ARIA attributes wherever possible (see ARIA Authoring Practices, number 7), makes for a pretty strong recommendation to use the aria attribute selectors. It has problems in IE6, but that's not even supported by Microsoft any more and I'm well past caring about it 😄

@miguelcobain
Copy link
Collaborator

@jmacqueen more context:

I'm not sure this results in a significant perf penalty, but it might be worth to try to quantify that penalty.

@jmacqueen
Copy link
Contributor

Ah. After looking at what they were replacing. That project was using a huge number of unqualified attribute selectors, which is the equivalent of doing a global select and then an attribute select on every rule. Very, very, very slow combination. And they had a TON of them in the layout module.

As long as there is some qualifier (e.g. .ember-basic-dropdown-trigger[aria-expanded="true"]) then there shouldn't be any problem performance-wise.

@miguelcobain
Copy link
Collaborator

@jmacqueen got it! Thanks for the explanation.

@cibernox
Copy link
Owner Author

@jmacqueen Thanks for investigating that. I never considered css selector performance as a critical thing before.

One downside of of using selectors like .ember-power-select-option[aria-dirabled="true"] is that this is a 2nd level selector, and has higher precedence than .ember-power-select-option--selected. That is a boomer for BEM lovers.

I could have mantained the classes but I didn't because

  1. Avoid redundancy
  2. Performance (The least bindings ember has to maintain, the best)
  3. Enforce a11y on anyone that wants to build their custom components but want to reuse styles.

Let's see how it goes.

@cibernox
Copy link
Owner Author

@jmacqueen

Search Box: include close button

Mmm.. there is no close button. I think that the button you see in chrome is because it's added by default by blink and webkit to input[type=search] things. Is that what you mean?

@jmacqueen
Copy link
Contributor

Hah! Yes! That's exactly what I mean. Oops.

In that case, it needs no special treatment. The browser will handle populating the AT (as it does for any other built-in interactive element).

@jmacqueen
Copy link
Contributor

re: CSS...how are you limiting your aria-disabled styling to be specific to power-select so it doesn't hit everything on the page with aria-disabled?

@cibernox
Copy link
Owner Author

I think I'm only targeting aria-disabled on the options and the trigger.

@jmacqueen
Copy link
Contributor

Is there a way to pass through aria-labelledby, aria-describedby, aria-required, aria-invalid, and/or aria-label from the {{power-select}} invocation into the {{basic-dropdown}} that I'm missing?

  • aria-labelledby
  • aria-describedby
  • aria-required
  • aria-invalid
  • aria-label

@cibernox
Copy link
Owner Author

cibernox commented Apr 4, 2016

@jmacqueen PR #254 should be resuscitated for that. @martndemus are you still interested in finish that?

@ghost
Copy link

ghost commented Apr 4, 2016

@cibernox Not really sure when I can commit to this, but if I have some time I sure would like to help 😄

@jmacqueen
Copy link
Contributor

Looking at it now. I think I was might have been unclear with my dropdown diagram back in February.

My intention was for role=button, aria-haspopup=true, aria-expanded=true/false, aria-pressed=true/false, and aria-controls=<id of dropdown> to be on the ember-basic-dropdown-trigger <div>, not the contained ember-power-select trigger. All of those semantics are particular to the dropdown state and best handled at that level...and duplicating that work should be unnecessary.

Ignore all of that. I spoke too quickly from a quick glance at the DOM. Looks like things are probably in the right place.

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

No branches or pull requests

4 participants