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

Make the multi-select selection area more accessible #5842

Merged
merged 10 commits into from
Apr 29, 2020

Conversation

kevin-brown
Copy link
Member

@kevin-brown kevin-brown commented Apr 26, 2020

This pull request includes a

  • Bug fix
  • New feature
  • Translation

The following changes were made

  • Switch from floating the selections to using inline-block elements
  • Move the search field outside of the selection list
  • Move the clear button outside of the selection list
  • Made the clear button use the <button> tag
  • Multiple select search is always full width when the placeholder is present

If this is related to an existing ticket, include a link to it as well.
Fixes #4418
Fixes #5585
Closes #5571

The selection search was previously being injected into the list of
selections. This was largely done because it was easier to style
and it matched up wiht how we injected the search box in older
version of Select2. Unfortunately it was pointed out to us that
this breaks the semantics of the list of selections, which is
definitely accurate and impacts accessibility.

The search box for selections, used primarily in multiple selects,
was moved to be next to the list of selections. Functionally, this
does not impact Select2 at all because of how we manage focus, but
it does impact the accessibility and styling of Select2. This moves
closer to bringing the Select2 selection area for multiple selects
into an accessible state, by pushing for the selections (the options
that were previously selected) to be within their own container and
to not interfere with other elements that may be present. This is
important because screen readers need to be able to read the current
selections and differentiate between elments.

This impacts the styling of Select2 internally, without impacting
how it visually looks to our users. We have switched from floating
all of the options to keep them visually in line to using a set of
inline-block elements that better reflect what is actually happening.
As a result, the base stylng as well as the styling for the default
and classic themes has been adjusted to use a set of inline-block
elements while maintaining any spacing between elements that
previously existed. Because the DOM ordering has changed, anyone
who was relying on DOM order instead of classes for styling the
search box will need to update their CSS to reflect the new
ordering. The same applies to any plugins which were relying on the
DOM to be stable in order to make changes.

This also switches the selection search to take up the full width
of the container when the placeholder is visible. This fixes a
long-standing issue where it was possible for the placeholder on
a multiple select to be hidden depending on the state of the DOM
at the time the placeholder was rendered.
The clear button was previously being injected at the start of the
rendered selection, creating invalid markup on multiple selects
where the rendered selection is a list, and overloading what the
rendered selection was for in single selects. It has now been moved
out of the rendered selection and it is now in front of the rendered
areas, allowing the clear button to still be floated to the right
over the rendered selection itself.

The clear button has also been changed to use a `<button>` element,
though it is still removed from the tab order. This allows for the
purpose to be properly communicated to screen readers while not
disrupting the natural tab order of the select box.

This affected the CSS across all themes because the positioning is
affected now that it is not located within the rendered container.
This required some small ajustments to get it to appear alongside
of the arrow within single select boxxes. This also required some
adjustments in order to get it to appear in the right location and
affect the rendering order within multiple selects, where the clear
button should push the search and selected choices down and around
it instead of appearing directly over it.

Because of the change to a `<button>` element, the clear icon may
render differently for some users because of the default stylesheet
rules. This may also come into play within themes where the `<button>`
elements may be styled differently.
@kevin-brown kevin-brown force-pushed the GH-5571-accessible-selection branch from 1cefdcb to 08b22a3 Compare April 26, 2020 20:59
This should make it more clear now what the current selections are
when the selection search is being used. In the future we may switch
this to pointing at a dedicated element which handles the accessibility
text representing the current selections, but for now we will rely
on the rendered selection to do the job.
This will ensure that when the button is clicked, any form that the
select is contained within is not triggered. This is because buttons
default to `type=submit` within forms.
This additional span is now being given a unique ID, similar to the
one which is given each result in the dropdown, and it is being
associated with the corresonding remove button for that choice. This
should not affect the rendering of the individual choices but it
does allow us to move forward on fixing accessibility issues around
the remove icon within multiple selects. Now when a remove icon is
focused by a screen reader, it should read out the text of the option
that would be removed.
This moves the remove item icon from being a span that can be clicked
to being an actual button that acts and behaves like a real button.
This means it is now using a `<button>` element and can receive
keyboard events to trigger the removal of an item, as well as the
mouse events it could previously receive.

Because the selection area can receive keyboard events that behave
differently from the removal of an item, a new handler needed to be
added for the remove button that stops the propagation of keyboard
events for it. This allows the enter key to propagate like it would
previously and trigger the click event.

This required some heavy adjustments to the CSS that will affects
themes. the click area for the remove item button is now larger and
visaully is separated from the text of the item itself. The
separation is done by a solid line to the right of the button which
can be removed by CSS if the user desires. The background of the
remove item button also visually changes now when the button is
hovered or focused, instead of before where it was only the text
color that changed. The classic theme does not incorporate most of
these changes.

This also updates the RTL theme to work with all of the styling
changes that have been made so far.
The clear button currently says "Remove all items" but it does not
provide any context to screen readers what items will be removed.
By adding the `aria-describedby` attribute, they will now announce
the selected options after annoying that the button is to remove
all items.
@kevin-brown
Copy link
Member Author

kevin-brown commented Apr 28, 2020

There are still a few things left to do in this pull request

  • Surround the &times; in remove buttons with an aria-hidden="true" element (probably a <span>)
  • Add a new translation for "Remove item" which can be used on the individual "remove" buttons for choices
  • Keyboard/tab accessibility for the "Remove item" buttons (will be handled in a future pull request, pending suggestions on how to do this right)

@kevin-brown kevin-brown marked this pull request as ready for review April 28, 2020 00:45
Previously screen readers would hear the "x" be read aloud within
the different clear/remove icons even though it does not serve an
actual purpose for them. This hides them so now it should only read
out the label and that's it.
This adds a title and aria-label attribute for the remove item
button. This should ensure that screen readers read out "Remove item"
followed by the item text when these icons are focused. This adds
a new translation for this text, but translations for languages
other than English will need to be added separately.
@Hosch250
Copy link

Hosch250 commented May 9, 2020

Sorry for being a bit late with this, but I propose something like the following structure for the remove-item button:

<button type="button">
    <span aria-hidden="true">x</span>
    <span class="sr-only">Remove {visible label}</span>  <!-- bootstrap class; you'll want to implement your version that's basically a copy/paste implementation -->
</button>

This allows the user to access the button with keyboard focus, and correctly announces which item they are going to delete. It also hides the 'x' glyph you are using for the visual, which gets announced weird in at least some common screen readers. I have used this (or a similar) format myself successfully in a project using the powerful templating support you have; the only thing I couldn't fix using that was the announcement of "blank" when keyboarding/hovering through the dropdown of selectable items.

@kevin-brown
Copy link
Member Author

I believe the current generated HTML for the remove button is (unrelated attributes not included)

<button type="button" aria-label="Remove item" title="Remove item" aria-describedby="id-of-item-text">
  <span aria-hidden="true">x</span>
</button>

The justification for doing this being that the "x" doesn't need to be made visible to screen readers (since, as you said, it gets announced weird in screen readers). As a replacement, the aria-label and aria-describedby are used with the goal of having it announced as "Remove item {visible label}" when focused by a screen reader.

Is there any chance you can confirm that this is what is read to screen readers using Select2 4.1.0-beta.1?

@Hosch250
Copy link

Hosch250 commented May 9, 2020

I just tested this, and the only problem is the tabindex="-1" prevents it from being focused, so the user can't remove an item with the keyboard. If I remove that attribute, the selected item(s) delete buttons get selected before the control.

It also doesn't announce the label tied to the multi-select field I connected it to; instead, it says something like "item has autocomplete; remove item test; blank". I was able to make this read (more) sensibly by performing the following actions (manually, in the DOM):

  • Remove the aria-describedby attribute from the input element; this fixes the selected items being read out every single time you tab to the field--especially when you just moved through them by hitting the x buttons.
  • Add an id to the field label (I was using the for attribute; this step wouldn't be necessary if the label already had an id).
  • Putting an aria-labelledby attribute on the input element pointing to this label (aria-labelledby="my-new-label"). Now it says something like "combobox collapsed; {header} headed has autocomplete; blank". I'm not sure where the "blank" part is coming from.

Otherwise, everything works really well.

@kevin-brown
Copy link
Member Author

@Hosch250 while I've got those noted down on my side as things to fix in the next beta release, is there any chance you can make a ticket or two for capturing those bugs? That would make it easier to track the issues and know when they have been resolved.

Thank you for testing this for us!

@Hosch250
Copy link

Done!

@nishantyadav151
Copy link

@kevin-brown and @Hosch250 is this resolve?
Issue: announcment of "Blank" by NVDA while focussing on the selected value.
Steps to reproduce:
The issue is in with the select box
Steps to reproduce:
1.Turn on NVDA.
2. Go to the selection box.
3. tab over to the state field(the State field is selctable) and tab out of it.
4. tab back to state field and it reads "State open combo box editable blank"

the expected behavior is not to say blank in the end.

blank items

anttikuuskoski pushed a commit to anttikuuskoski/select2 that referenced this pull request Mar 29, 2022
* Move selection search out of list

The selection search was previously being injected into the list of
selections. This was largely done because it was easier to style
and it matched up wiht how we injected the search box in older
version of Select2. Unfortunately it was pointed out to us that
this breaks the semantics of the list of selections, which is
definitely accurate and impacts accessibility.

The search box for selections, used primarily in multiple selects,
was moved to be next to the list of selections. Functionally, this
does not impact Select2 at all because of how we manage focus, but
it does impact the accessibility and styling of Select2. This moves
closer to bringing the Select2 selection area for multiple selects
into an accessible state, by pushing for the selections (the options
that were previously selected) to be within their own container and
to not interfere with other elements that may be present. This is
important because screen readers need to be able to read the current
selections and differentiate between elments.

This impacts the styling of Select2 internally, without impacting
how it visually looks to our users. We have switched from floating
all of the options to keep them visually in line to using a set of
inline-block elements that better reflect what is actually happening.
As a result, the base stylng as well as the styling for the default
and classic themes has been adjusted to use a set of inline-block
elements while maintaining any spacing between elements that
previously existed. Because the DOM ordering has changed, anyone
who was relying on DOM order instead of classes for styling the
search box will need to update their CSS to reflect the new
ordering. The same applies to any plugins which were relying on the
DOM to be stable in order to make changes.

This also switches the selection search to take up the full width
of the container when the placeholder is visible. This fixes a
long-standing issue where it was possible for the placeholder on
a multiple select to be hidden depending on the state of the DOM
at the time the placeholder was rendered.

* Moved clear button out of rendered selection

The clear button was previously being injected at the start of the
rendered selection, creating invalid markup on multiple selects
where the rendered selection is a list, and overloading what the
rendered selection was for in single selects. It has now been moved
out of the rendered selection and it is now in front of the rendered
areas, allowing the clear button to still be floated to the right
over the rendered selection itself.

The clear button has also been changed to use a `<button>` element,
though it is still removed from the tab order. This allows for the
purpose to be properly communicated to screen readers while not
disrupting the natural tab order of the select box.

This affected the CSS across all themes because the positioning is
affected now that it is not located within the rendered container.
This required some small ajustments to get it to appear alongside
of the arrow within single select boxxes. This also required some
adjustments in order to get it to appear in the right location and
affect the rendering order within multiple selects, where the clear
button should push the search and selected choices down and around
it instead of appearing directly over it.

Because of the change to a `<button>` element, the clear icon may
render differently for some users because of the default stylesheet
rules. This may also come into play within themes where the `<button>`
elements may be styled differently.

* Add aria-describedby to selection search

This should make it more clear now what the current selections are
when the selection search is being used. In the future we may switch
this to pointing at a dedicated element which handles the accessibility
text representing the current selections, but for now we will rely
on the rendered selection to do the job.

* Set `type=button` on the "clear all" button

This will ensure that when the button is clicked, any form that the
select is contained within is not triggered. This is because buttons
default to `type=submit` within forms.

* Render choices inside additional span

This additional span is now being given a unique ID, similar to the
one which is given each result in the dropdown, and it is being
associated with the corresonding remove button for that choice. This
should not affect the rendering of the individual choices but it
does allow us to move forward on fixing accessibility issues around
the remove icon within multiple selects. Now when a remove icon is
focused by a screen reader, it should read out the text of the option
that would be removed.

* Make the remove item button an actual button

This moves the remove item icon from being a span that can be clicked
to being an actual button that acts and behaves like a real button.
This means it is now using a `<button>` element and can receive
keyboard events to trigger the removal of an item, as well as the
mouse events it could previously receive.

Because the selection area can receive keyboard events that behave
differently from the removal of an item, a new handler needed to be
added for the remove button that stops the propagation of keyboard
events for it. This allows the enter key to propagate like it would
previously and trigger the click event.

This required some heavy adjustments to the CSS that will affects
themes. the click area for the remove item button is now larger and
visaully is separated from the text of the item itself. The
separation is done by a solid line to the right of the button which
can be removed by CSS if the user desires. The background of the
remove item button also visually changes now when the button is
hovered or focused, instead of before where it was only the text
color that changed. The classic theme does not incorporate most of
these changes.

This also updates the RTL theme to work with all of the styling
changes that have been made so far.

* Add aria-describedby to clear button

The clear button currently says "Remove all items" but it does not
provide any context to screen readers what items will be removed.
By adding the `aria-describedby` attribute, they will now announce
the selected options after annoying that the button is to remove
all items.

* Hide the "x" in the remove icons from screen readers

Previously screen readers would hear the "x" be read aloud within
the different clear/remove icons even though it does not serve an
actual purpose for them. This hides them so now it should only read
out the label and that's it.

* Add helper text for the remove item button

This adds a title and aria-label attribute for the remove item
button. This should ensure that screen readers read out "Remove item"
followed by the item text when these icons are focused. This adds
a new translation for this text, but translations for languages
other than English will need to be added separately.

* Add aria-label for remove all button
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Placeholder not showing Input with items already selected reads blank when focused with NVDA
3 participants