phetsims / a11y-research

a repository to track PhETs research into accessibility, or "a11y" for short
MIT License
3 stars 0 forks source link

Create accessible combobox #64

Closed terracoda closed 5 years ago

terracoda commented 6 years ago

Gathering resources for combobox:

terracoda commented 6 years ago

@jessegreenberg , @zepumph , @mbarlow12 I have coded up an HTML select box. I have a feeling that might be way simpler than a custom combobox.

Please have a look in the html-sketches folder: combobox/combobox-examples.html

terracoda commented 6 years ago

I am going to put the design notes here in the issue and remove them from the example html.

terracoda commented 6 years ago

Here's the draft visual highlighting Functionally, both the Up and Down Arrow keys activate (pop-up) the collapased list of options. We may want to consider adjusting the visual prompt which only indicates the Up Arrow. Also in the visual, a selected item is not visually indicated. We may want to consider adding a visual checkmark (or some visual cue) to visually indicate which item is currently selected.

  1. Combobox gains focus with the Tab key (or other method). I don't think we need the checkmark on the selected item when the combobox is collapsed. molarity-combobox-focused

  2. Space key, Up Arrow, or Down Arrow open the list of solutes. The selected item has focus when the combobox is opened. A visual checkmark has been added for emphasis. molarity-selected-item-focused

  3. Focus highlight moves with Up and Down Arrow keys, and the selected item stays checked until a new selection is made by pressing the Enter key. Combobox closes when a new item is selected with the Enter key or Space key. Escape key also closes the list of options without making a change in selection. molarity-unselected-item-focused

Note: I updated key presses.

terracoda commented 6 years ago

Example 1: HTML Design Pattern (working example) The HTML design pattern uses the select element with a solutes codes as option elements. This works out-of-the-box with keyboard navigation and in Voice Over on Safari. The HTML size attribute can be used to make a designated number of options persist visually; however, this is undesirable in this case, and likely for most of PhET's interactive sim elements of this type (i.e., pop-up menus/comboboxes).

<label for="solute-options">Solute:</label>
<select id="solute-options" name="select">
  <option value="1">Drink mix</option>
  <option value="2">Colbalt (II) nitrate</option>
  <option value="3">Colbalt Chloride</option>
  <option value="4">Potassium dichromate</option>
  <option value="5">Gold (III) chloride</option>
  <option value="6">Potassium chromate</option>
  <option value="7">Nickel (II) chloride</option>
  <option value="8">Copper sulfate</option>
  <option value="9">Potassium permanganate</option>
  <option value="10">Potassium dichromate</option>
</select>

Example 2: ARIA 1.0 Design Pattern (non-working example) The ARIA 1.1 design pattern is not yet supported. Both the 1.1 and 1.0 design patterns seem very complicated to me. And since our PDOM is visually hidden, I think the HTML solution in Example 1, above, is better for us.

In ARIA 1.1, therole=”combobox” is now a composite widget, meaning that it supports child element roles including active element roles embedded within it. However, the design pattern is too new to use.

In the ARIA 1.0 design pattern example below, there are three attributes on the focusable HTML input element that has the role="combobox" that have to be maintained dynamically.

These are:

I think in our case the widget is read-only, as it is not editable, but placing the HTML5 readonly attribute on the input element removes the element from the Tab order. The code below is a non-working example. See Whatsock for a working example. This is the pattern I tried to follow.

<input id="solute-comboxbox" tabindex="0" aria-label="Solute" type="text"
 role="combobox" aria-expanded="false" aria-autocomplete="list" 
aria-controls="owned-solute-listbox" aria-activedescendent="" readonly>
<ul role="listbox" id="owned-solute-listbox">
  <li role="option" id="solute-option-01">Drink mix</li>
  <li role="option" id="solute-option-02">Colbalt (II) nitrate</li>
  <li role="option" id="solute-option-03">Colbalt Chloride</li>
  <li role="option" id="solute-option-04">Potassium dichromate</li>
  <li role="option" id="solute-option-05">Gold (III) chloride</li>
  <li role="option" id="solute-option-06">Potassium chromate</li>
  <li role="option" id="solute-option-07">Nickel (II) chloride</li>
  <li role="option" id="solute-option-08">Copper sulfate</li>
  <li role="option" id="solute-option-09">Potassium permanganate</li>
  <li role="option" id="solute-option-10">Potassium dichromate</li>
</ul>
jessegreenberg commented 6 years ago

Thanks for working on this @terracoda, looks great and nice mockups!

I think we ran into trouble with the <select> box because we couldn't figure out how to hide the options in the parallel DOM. @zepumph am I remembering this correctly? @terracoda do you know of a way to make the select box drop down and options invisible with CSS?

If it can't be hidden, we might be stuck with an ARIA pattern.

jessegreenberg commented 6 years ago

The Whatsock example is working really nicely, I agree it is very complicated.

terracoda commented 6 years ago

For me the Whatsock example does not read out the individual options in VO and Safari. I only hear the selected language.

jessegreenberg commented 6 years ago

Good to know @terracoda, thanks

terracoda commented 6 years ago

@jessegreenberg can you explain what you mean by "hide the options in the PDOM".

  1. When using VO I only hear the options when the pop-up is open. I can't find any other options in the PDOM with the cursor keys when the pop-up is closed.
  2. Without VO on, however, when using the keyboard alone, I can arrow through the options with the Right and Left arrow keys without first popping up the list of options with the Up or Down Arrow keys.

@jessegreenberg, are you concerned about number 2? or something else? Number 2 seems natural to me, but might complicate implementation.

We might be able to restrict access to the options until the pop-up is actually open. I'd have to play with some things (hidden, aria-hidden, aria-expanded, css, etc). The size attribute doesn't seem to have any effect when set to 1.

I'll wait for @zepumph to comment with details because right now select and option seem to work beautifully for me out of the box.

jessegreenberg commented 6 years ago

The problem is that the HTML select box needs to be invisible for sighted users. The last time we tried to use select, we couldn't figure out how to make the options box invisible. Take a look at this example: https://jsfiddle.net/Lfbea747/show/ (You can see the HTML here: https://jsfiddle.net/Lfbea747)

Click in the grey box under 'Show' and press enter, and you will still see the box of options even though the select box is hidden. We couldn't figure out a way to hide this box with CSS, but there could certainly be a way we didn't think of. If we could use select I agree that would be the most straight forward.

terracoda commented 6 years ago

@jessegreenberg, I don't understand how jsfiddle is supposed to work, but does this work?

<div style="text-indent: -1000em;">
<label for="solute-options">Solute:</label>
<select id="solute-options" name="solute-options">
  <option value="1">Drink mix</option>
  <option value="2">Colbalt (II) nitrate</option>
  <option value="3">Colbalt Chloride</option>
  <option value="4">Potassium dichromate</option>
  <option value="5">Gold (III) chloride</option>      
  <option value="6">Potassium chromate</option>
  <option value="7">Nickel (II) chloride</option>
  <option value="8">Copper sulfate</option>
  <option value="9">Potassium permanganate</option>
  <option value="10">Potassium dichromate</option>
</select>
</div>

I think we may need to look seriously at how we are hiding the PDOM. Ideally, the entire thing is hidden in the same way.

terracoda commented 6 years ago

@jessegreenberg I see what you mean now. The grey box seems to return visually, eventhough everything is moved off screen.

This needs some investigation.

jessegreenberg commented 6 years ago

@terracoda I tried text-indent: -1000em;, it works great in Chrome! But the box still shows up at the very left edge of the screen in Safari.

terracoda commented 6 years ago

@jessegreenberg, yes, same with Safari. The position of the box is very persistent.

terracoda commented 6 years ago

@jessegreenberg, it finally disappeared with an option focus style applied. I'm not sure how robust this is, but I do not see the list of options or anything else in Safari.

In the head...

<style>
  .hide-me {
    text-indent: -1000em;
  }
  option:focus{
    display: block;
    text-indent: -1000em;  
  }  
  </style>

And in the body...

<div class="hide-me">
  <label for="solute-options">Solute:</label>
  <select id="solute-options" name="solute-options" size="1">
    <option value="1">Drink mix</option>
    <option value="2">Colbalt (II) nitrate</option>
    <option value="3">Colbalt Chloride</option>
    <option value="4">Potassium dichromate</option>
    <option value="5">Gold (III) chloride</option>
    <option value="6">Potassium chromate</option>
    <option value="7">Nickel (II) chloride</option>
    <option value="8">Copper sulfate</option>
    <option value="9">Potassium permanganate</option>
    <option value="10">Potassium dichromate</option>
  </select>
</div>
terracoda commented 6 years ago

A negative left margin also seems to work.

terracoda commented 6 years ago

For example:

<style>
  .hide-me {
    margin-left: -1000em;
  }
  option:focus{
    display: block;
    margin-left: -1000em;  
   }
  </style>
jessegreenberg commented 6 years ago

Awesome, thanks @terracoda! Unfortunately I tried the above in a JSFidddle and it didn't work for us in Safari, the box of options kept appearing. Would you mind sending a JSFiddle with it working in case we didn't use the right CSS? Or we could do a voice chat and share screens some time.

terracoda commented 6 years ago

@jessegreenberg, did you try the actual HTML file on github?

jessegreenberg commented 6 years ago

I just tried https://github.com/phetsims/a11y-research/blob/master/html-sketches/combobox/combobox-examples.html, I can see the box in Safari 10.0.1 when I open it with spacebar.

EDIT: it is hidden correctly in Chrome.

terracoda commented 6 years ago

Oh, I seemed to have been incorrect. I get the pop-up in Safari 11.01, too.

terracoda commented 6 years ago

Would this "detaching" method work in our situation? https://stackoverflow.com/questions/4398966/how-can-i-hide-select-options-with-javascript-cross-browser

jessegreenberg commented 6 years ago

@terracoda I think that solution with .detach() is actually removing the elements from the DOM, not just hiding them. One thing I noticed was that the box looks different when the size attribute is used, and I am wondering if using size will prevent a box from being shown visually. @terracoda do you know if the size attribute will have an impact on how AT interpret this element?

terracoda commented 6 years ago

@jessegreenberg, I did test the size attribute. When I set it to 10, the box is always open and it looks different. I didn't try to move it off screen. There was no difference to AT that I noticed. I could check again.

terracoda commented 6 years ago

@jessegreenberg, it stays off screen with size="10", and it does change the announcement a little in VO. Instead of the select being described as a pop-up button, it is described as a listbox. Arrow keys still navigation up and down and Enter changes active selection.

terracoda commented 6 years ago

@jessegreenberg, when using the negative text-indent offscreen method, the select with size of 10 does take up vertical space, though it is not visible. Using a positioning technique might solve that issue.

terracoda commented 6 years ago

@jessegreenberg, the default interaction for the listbox items has them autoselect. The selected item is announced upon focus. Navigating with Arrow keys autoselects item (without overt announcement). Typing the first letter of a solute jumps to that solute (e.g. G jumps to Gold). Tabbing away, "Leaving listbox" is announced, and then when returning to Listbox, the last item read out is read out as the selected item with it's place in the list(3 of 10).

terracoda commented 6 years ago

@jessegreenberg , fn key and Up/Down Arrow go to first and last items.

terracoda commented 6 years ago

@jessegreenberg, got it.

Here's the css

  .hide-me {
      position: relative;
  }

.hide-me select,
.hide-me label {
      position: absolute;
      left: -999em;  
  }

Here's the HTML

<div class="hide-me">
  <label for="solute-options">Solute:</label>
  <select id="solute-options" name="solute-options" size="10">
    <option value="1">Drink mix</option>
    <option value="2">Cobalt (II) nitrate</option>
    <option value="3">Cobalt Chloride</option>
    <option value="4">Potassium dichromate</option>
    <option value="5">Gold (III) chloride</option>
    <option value="6">Potassium chromate</option>
    <option value="7">Nickel (II) chloride</option>
    <option value="8">Copper sulfate</option>
    <option value="9">Potassium permanganate</option>
    <option value="10">Potassium dichromate</option>
  </select>
</div>
terracoda commented 6 years ago

@jessegreenberg, brilliant idea about revisiting the size attribute.

terracoda commented 6 years ago

Commit https://github.com/phetsims/a11y-research/commit/f27180782fa35ed441d91f2f31c065ee6a06359c makes changes in the sample html sketch for a combox.

terracoda commented 6 years ago

@jessegreenberg, the listbox stays hidden, but still operable in Safari with VO. There are a couple of quirks with key presses (e.g., first down arrow key press is not read out) that we might need to look more deeply at.

This listbox thing, may still be easier than the ARIA 1.0 combobox.

jessegreenberg commented 6 years ago

Awesome, great work @terracoda I just verified that the box remains hidden in Safari 10.0.1!

jessegreenberg commented 6 years ago

One remaining question is how we will synchronize the select with the styling of the ComboBox in sun. HTML Events input and change don't fire until an option is selected with enter or spacebar. And the option element itself does not receive focus from the browser. So in order to update the display, we will have to listen for keydown events and somehow detect changes to the select box to support the features @terracoda listed in https://github.com/phetsims/a11y-research/issues/64#issuecomment-349978506 https://github.com/phetsims/a11y-research/issues/64#issuecomment-350336905 https://github.com/phetsims/a11y-research/issues/64#issuecomment-350341231

The next step will be to determine if we can detect keydown on select element when VO, JAWS, and NVDA are enabled, and if we can figure out which option is hovered.

Then we will need to figure out how to detect which option has the blue background when the box is open and we are navigating with arrow keys.

jessegreenberg commented 6 years ago

@mbarlow12 would you mind looking into https://github.com/phetsims/a11y-research/issues/64#issuecomment-350385303 in a JSFiddle or HTML page outside of a sim?

terracoda commented 6 years ago

@jessegreenberg and @mbarlow12, there may be some flexibility in the interaction patterns for listbox that can be made similar to a select box.

terracoda commented 6 years ago

I would suggest reading the design patterns for listbox and select and see where they are similar and/or different.

jessegreenberg commented 6 years ago

@terracoda is listbox an ARIA role or an HTML element?

terracoda commented 6 years ago

@jessegreenberg great question. listbox is an aria role, not an HTML element. However, some how when I added the size="10" the select element, it automatically took on the role of listbox. At least that is how it is described and how it seems to work in Voice Over in Safari.

jessegreenberg commented 6 years ago

Interesting, thanks.

At least that is how it is described and how it seems to work in Voice Over in Safari.

Is this OK, and do you think it sounds good enough in VO to continue using select?

terracoda commented 6 years ago

@jessegreenberg and @zepumph, I am going to read over the keyboard design pattern for the listbox and see how it intersects with the native select element pattern. The first obvious difference is listbox items autoselect, but that might be optional.

terracoda commented 6 years ago

I have added code example for listbox from MDN. I have not been able to successfully label it, and it currently is not dynamic. Regardless, it seems like a potential option for us.

  <div id="label-listbox1">Solute 3</div>
  <div role="listbox" tabindex="0" id="listbox1" onclick="return listItemClick(event);" 
      onkeydown="return listItemKeyEvent(event);" onkeypress="return listItemKeyEvent(event);" 
      onfocus="this.className='focus';" onblur="this.className='blur';" aria-activedescendant="listbox1-2" aria-labelledby="label-listbox1">
    <div role="option" id="listbox1-1">Drink mix</div>
    <div role="option" id="listbox1-2" class="selected" aria-selected="true">Cobalt (II) nitrate</div>
    <div role="option" id="listbox1-3">Cobalt Chloride</div>
    <div role="option" id="listbox1-4">Potassium dichromate</div>
    <div role="option" id="listbox1-5">Gold (III) chloride</div>
    <div role="option" id="listbox1-6">Potassium chromate</div>
    <div role="option" id="listbox1-7">Nickel (II) chloride</div>
    <div role="option" id="listbox1-8">Copper sulfate</div>
    <div role="option" id="listbox1-9">Potassium permanganate</div>
    <div role="option" id="listbox1-10">Potassium dichromate</div>
  </div>
terracoda commented 6 years ago

Using a list instead of divs does not seem to change any semantics in Voice Over.

terracoda commented 6 years ago

Added the code example with un-ordered list code. Key presses not fully implemented. This would require a developer's help.

<h3 id="label-listbox4">Solute 4</h3>
  <ul role="listbox" tabindex="0" id="listbox4" onclick="return listItemClick(event);" 
      onkeydown="return listItemKeyEvent(event);" onkeypress="return listItemKeyEvent(event);" 
      onfocus="this.className='focus';" onblur="this.className='blur';" aria-activedescendant="listbox4-4" aria-labelledby="label-listbox4" style="list-style:none;">
    <li role="option" id="listbox4-1">Drink mix</li>
    <li role="option" id="listbox4-2">Cobalt (II) nitrate</li>
    <li role="option" id="listbox4-3">Cobalt Chloride</li>
    <li role="option" id="listbox4-4" class="selected" aria-selected="true">Potassium dichromate</li>
    <li role="option" id="listbox4-5">Gold (III) chloride</li>
    <li role="option" id="listbox4-6">Potassium chromate</li>
    <li role="option" id="listbox4-7">Nickel (II) chloride</li>
    <li role="option" id="listbox4-8">Copper sulfate</li>
    <li role="option" id="listbox4-9">Potassium permanganate</li>
    <li role="option" id="listbox4-10">Potassium dichromate</li>
  </ul>
terracoda commented 6 years ago

@jessegreenberg, sorry missed comment https://github.com/phetsims/a11y-research/issues/64#issuecomment-350400941

Re your question:

Is this OK, and do you think it sounds good enough in VO to continue using select?

So far, the select with size attribute (i.e. select/listbox) sounds better than the other listbox examples I have added to the mock-up. I thought is was worth exploring a couple of code options to test in different environments. The biggest issue with the select/listbox seems to be the hiding of the actual options box. If that is resolved, and if it sounds good on all platforms, then I think it is our best option, thus far.

Two things I think we should consider:

  1. A listbox that is not part of a select element may be easier to hide.
  2. If we go with anything that has the listbox role, we need to consider the best keyboard pattern (i.e., auto-selection on focus or not, type ahead or not, etc.)
terracoda commented 6 years ago

I added example 4 which adds a listbox with a list structure to the mock-up.

terracoda commented 6 years ago

@jessegreenberg, do think it is worth trying to program in a listbox interaction that does not move selection with focus to see what it sounds like in different AT?

My examples do not have the full keyboard interactions built in.

terracoda commented 6 years ago

How the default Select box interaction works in Safari:

I think it is within the ARIA Best Practices to make either a Select/listbox or an ARIA listbox behave like the above Select box interaction.

Do people think that is reasonable way to go?

terracoda commented 6 years ago

@jessegreenberg and @zepumph I showed and explained Example 1 (hidden) and Example 4 to @emily-phet and she thought it was worth implementing the Example 1 (hidden) and Example 4 in Molarity with the Select element interaction pattern to see which code works best across Browser and AT combos.

jessegreenberg commented 6 years ago

Great, thanks for collecting this list @terracoda, that is really helpful. Also great to see a listbox example. So I think our priority of investigation should be to:

@mbarlow12 would you be able to investigate the first bullet point? We can pair on this the next time you are available if you like.