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

How to handle Space vs Enter for buttons #939

Closed
Tracked by #953
zepumph opened this issue Jan 28, 2019 · 78 comments
Closed
Tracked by #953

How to handle Space vs Enter for buttons #939

zepumph opened this issue Jan 28, 2019 · 78 comments
Assignees

Comments

@zepumph
Copy link
Member

zepumph commented Jan 28, 2019

From #934, in the browser they are different, @pixelzoom and @zepumph discussed at one point whether or not that adds value to phetsims, it would be good to discuss that further, and then implement from there. This also may relate to how we are handling sun buttons, and that should be looked at in this issue to.

Related potentially to phetsims/sun#424, there is likely little use for the default behavior of Enter to be fire multiple events.

Even though it is browser default, we know we want to support users at PhET that are younger, and may not have as much keyboard experience, it could easily be overwhelming to have a button fire many times without a good, pedagogical reason to. Expanding on that, then why would we make that the default behavior for Enter?

I think from discussing with @pixelzoom that we are mostly in agreement (correct me if I'm wrong) that the default behavior for both should (a) be the same, and (b) be a single click for buttons. See #931 for adding support for options that would deal with "fire on hold" features.

@emily-phet
Copy link

I believe @zepumph will bring this up in today's meeting. Some things that seem relevant to go over in that meeting include:

  • This may be obvious, but it would be helpful (at least for me) to have a reminder of expected behavior for space vs enter.
    Presumably both activate a button. Does Enter only activate buttons? (e.g., drop downs, comboboxes, generic buttons, reset all button, etc. - anything implemented as a 'button')? And does space activate buttons (and all that are implemented as buttons), checkboxes, anything else?

  • Also relevant - users have the ability to control what happens on holding a key down using sticky keys (and probably other things). We wouldn't want to preclude a user from controlling what happens on hold in their usual ways, if we can avoid it (I'm thinking about 'regular button presses' vs 'fire on hold' button presses).

  • Another thought - I think someone mentioned in Interval for firing button listeners when holding down enter key sun#424 that the OS manages how long the delay is on hold. I think we've done this as well, for example with the arrow key interaction to move the ruler in GFL REGULAR. This might be relevant to the conversation. Maybe having a pretty long delay for enter before repeated fires on hold - and maybe a shorter delay for 'fire on hold' buttons.

@jessegreenberg
Copy link
Contributor

Our buttons respond to the click event which is triggered at various times depending on whether or not an assistive device is in use. When an assistive device is enabled the click event is usually not accompanied by keydown or keyup events. For example, the events shown in this test will be different depending on whether NVDA is enabled: https://jsfiddle.net/gtjnfw8d/4/

Since we can't always listen to keyup and keydown, I don't see a way we can detect key releases to make enter and spacebar behave the same way or only fire buttons once per key press.

Having a good way to delay firing listeners on the click event in #931 seems like our best option.

@pixelzoom
Copy link
Contributor

pixelzoom commented Jan 29, 2019

@emily-phet said:

.... Maybe having a pretty long delay for enter before repeated fires on hold - and maybe a shorter delay for 'fire on hold' buttons.

This would match how "fire on hold" typically works. Both the delay and interval should be configurable. Some PhET UI components have this feature, some do not. Sun push buttons do support this feature, see PushButtonModel:

      // fire-on-hold feature
      fireOnHold: false,
      fireOnHoldDelay: 400, // start to fire continuously after pressing for this long (milliseconds)
      fireOnHoldInterval: 100, // fire continuously at this interval (milliseconds)

@pixelzoom
Copy link
Contributor

pixelzoom commented Jan 29, 2019

@jessegreenberg said:

... Since we can't always listen to keyup and keydown, ...

Why can't we? And why are we explicitly writing handlers that listener for click? Should we be using a scenery listener that abstracts out those specifics?

@jessegreenberg
Copy link
Contributor

When an assistive device is enabled the click event is usually not accompanied by keydown or keyup events.

Assistive devices can change which DOM events are sent, even for identical user interactions. For instance, press "enter" on a button without NVDA and keydown, click, keyup events will be sent in that order. But turn on NVDA and ONLY the click DOM event will be sent. There are no keydown or keyup events to listen for. That is why we are writing handlers for click.

@pixelzoom
Copy link
Contributor

Hmm... Then ComboBox will need to change - it's currently listening for keyup (it was previously listening for keydown.) And why are things like PhetMenu looking for keydown? Do those need to change?

Are keydown and keyup only absent with NVDA for Space and Enter? I'm guessing that must be the case, otherwise we couldn't get other key presses (arrows, etc.)

@jessegreenberg
Copy link
Contributor

The DOM events are determined by the role of the element that has focus. In ComboBox, focus is on an element with the ARIA role option, so keyup will be received. For elements with the button role, keydown and keyup are never sent for any key press. This is so the user can continue to read with the virtual cursor if focus is on a button. For example, pressing "b" while focus is on a button with screen reader enabled will not send a keydown event, but move focus to the next button in the page.

@zepumph
Copy link
Member Author

zepumph commented Jan 29, 2019

Here is a stack overflow I found that helps describe why the default browser behavior is the way it is

https://stackoverflow.com/questions/16090578/why-do-enter-and-space-keys-behave-differently-for-buttons

@pixelzoom
Copy link
Contributor

pixelzoom commented Jan 29, 2019

Re the stackoverflow article... I see conjecture, but no authoritative reference. If we accept this hypothesis, which is in the response with the largest number of votes:

Enter is to accept, Esc is to reject, Space bar is to press the focused button. So if the default button is the OK, when you press Enter you actually accept the changes and not press the button.

If the semantics of Enter are "accept", then why does it fire repeatedly when the button is held down?

@pixelzoom
Copy link
Contributor

@jessegreenberg Thanks for the clarification. I didn't realize that you were referring exclusively to elements with role button.

@pixelzoom
Copy link
Contributor

Here's something else that makes no sense to me, observed in the current implementation of ComboBox. If the combo box button has focus, pressing Enter pops up the listbox, and releasing Enter immediately pops down the listbox.

Demonstrated in Molarity:

  1. Tab to the combo box, so that its button has focus.
  2. Press and hold the Enter key. The button's click listener fires. The listbox pops up and the item that is currently selected is given focus.
  3. Release the Enter key. The selected item's keyup listener fires, and the listbox pops down.

So by clicking Enter (which supposedly means "accept") the related events get sent to whatever UI component happens to have focus at the time. That Enter was meant for the button, and only the button. The listbox and its items shouldn't be receiving anything related to that user action.

@jessegreenberg
Copy link
Contributor

jessegreenberg commented Jan 31, 2019

That is another problem, and also happens with click event, not just keyup https://jsfiddle.net/3bgkcdes/ We should have a general solution for this if possible, though the challenges will come from the same lack of events we face in this issue.

I think we should create another issue to investigate this (#942). Working on the timing for firing buttons with the keyboard (probably in PressListener) will be continued in #931. Does everyone agree that this can be closed?

@terracoda
Copy link

@zepumph, @pixelzoom, @jessegreenberg, currently from phettest and using Safari on Mac OS (with or without a screen reader on), the button that pops up the the list of options is not operable with the Enter key, only the Space key.

It's a button, so it needs to be operable via the Enter key.

Perhaps this article by Paul J. Adam from Deque on building accessible buttons will help us gain some understanding. It is important to note, however, that our implementation is a pop-up button. I don't think we are using aria-expanded, but rather, aria-haspopup="listbox".

Note, we are using a real button, more specifically, a real pop-up button so our job should be a lot easier.
From article:

When a JavaScript onclick event is attached to a native or the keyboard accessibility for both Enter and Spacebar keys is included for free and you don’t need a role attribute.

Further down in the article, for native button's:

To make a button keyboard operable all you need is the onclick event and it works with Enter and Spacebar keys!

The pattern that we adapted for the PhET Combobox if I am remembering correctly from the example of a Collapsible Drop Down List. Of course, we pop up rather than down.

The short of it is that we need the Enter key to work on the button that pops up the list.

Enter key should pop up the list and the list should stay visible with focus shown on the selected solute until Space, Enter or Esc are pressed. Arrow keys are used to move focus within the list of options.

@terracoda
Copy link

I think we can close this issue if we agree that we should be supporting both Space and Enter keys on buttons.

@terracoda terracoda removed their assignment Feb 1, 2019
@terracoda
Copy link

Please re-assign to me as needed.

@terracoda
Copy link

Adding links to previous research in other issues
phetsims/a11y-research#64 and phetsims/sun#314

I appreciate all the effort going into the PhET Combobox!

@pixelzoom
Copy link
Contributor

@terracoda reported:

... currently from phettest and using Safari on Mac OS (with or without a screen reader on), the button that pops up the the list of options is not operable with the Enter key, only the Space key.

Thanks @terracoda. This specific issue with ComboBox is being tracked in phetsims/sun#447. A general solution is preferrable, and workaround in ComboBox is a last resort, and we've been deferring that issue until this more general issue is addressed.

@pixelzoom
Copy link
Contributor

pixelzoom commented Feb 1, 2019

@terracoda said:

I think we can close this issue if we agree that we should be supporting both Space and Enter keys on buttons.

I DO think we're all in agreement that Enter and Space both need to be tracked. But this issue deals with how to support them both. Specifically, we need to address differences when Enter and Space fire, how and when events are delivered to the sim, click vs keyup vs keydown approaches, what should happen when either button is held down, what options should be available to the programmer (e.g. fireOnHold and associated delays), what should be handled by Scenery event listener, etc. So I think we have some work to do before this issue is ready to close.

@pixelzoom
Copy link
Contributor

pixelzoom commented Mar 3, 2019

In preparation for 3/3/19 conference call, I did a deeper dive into the ARIA references that @terracoda provide in #939 (comment), as well as the HTML5 specifications. I was looking for info relevant to this issue, especially ways that we might customize the ARIA button role to better align with PhET button behavior. Here are some chunks of information and questions that I thought might be relevant. (Apologies to readers who already know this, or have already investigated these questions.)

  • So that's we're all on board with terminology... In the ARIA specification, “button activation” is what PhET has referred to as “button firing”. When a button is activated (fired), the action(s) associated with the button should be performed.

  • Regarding UX, we haven't been able to answer these 2 questions: Why does activation of Enter vs Space behave so differently? What activation behavior (if any) do users expect? Unfortunately when Enter and Space are mentioned for ARIA roles, the specification is vague and doesn't describe default behavior. For example, from the description of button role at https://www.w3.org/TR/wai-aria-practices-1.1/#button:

When the button has focus:

  • Space: Activates the button.
  • Enter: Activates the button.
  • While I could find no ARIA specification of the activation behavior for Enter and Space keys, I did find a section in the HTML5 spec that defines Activation in general, see https://www.w3.org/TR/html5/editing.html#activation.
    Question: Can we customize button activation behavior?

  • HTML buttons have an optional type attribute, see
    https://www.w3.org/TR/html5/sec-forms.html#the-button-element. The type attribute “controls the behavior of the button when it is activated.”
    Question: Have we investigated how button activation changes depending on the value of the type attribute?

  • ARIA button has an optional aria-pressed attribute, used to determine whether a button is pressed. See https://www.w3.org/TR/wai-aria-1.1/#button. This attribute is typically used only for toggle buttons, but perhaps we could leverage it for other buttons.
    Question: Can we use the aria-pressed attribute to provide more context for interpreting click events? (EDIT: After further reading, using aria-pressed for non-toggle buttons doesn't sound like a good idea.)

@pixelzoom
Copy link
Contributor

pixelzoom commented Mar 3, 2019

More about the click event that has been mentioned extensively in this issue, followed by a couple of questions...

The click event is a synthetic (DOM) event, specified in https://www.w3.org/TR/uievents/#click. It is synthesized in response to other events (e.g. keydown, keyup).

https://www.w3.org/TR/html5/webappapis.html#fire-a-click-event defines what a click event is:

Firing a click event means firing a synthetic mouse event named click, which bubbles and is cancelable.

https://www.w3.org/TR/html5/webappapis.html#firing-a-synthetic-mouse-event-named-e
defines what “firing a synthetic mouse event” means.

https://www.w3.org/TR/html5/editing.html#dom-htmlelement-click describes what happens when a click event is synthesized:

The click() method must run the following steps:
1 If the element is a form control that is disabled, abort these steps.
2 Run synthetic click activation steps on the element.

The steps involved in “run synthetic click activation steps” are defined in the Activation section of the spec, mentioned above and at https://www.w3.org/TR/html5/editing.html#activation. These steps appear to be customizable.

Question: Do any of the click event fields provide us with useful information?

Question: Can synthesis of the click event be customized?

@pixelzoom
Copy link
Contributor

pixelzoom commented Mar 3, 2019

ARIA examples for role=button are at https://www.w3.org/TR/2016/WD-wai-aria-practices-1.1-20160317/examples/button/button.html#. (EDIT: Newer version of this webpage might be https://www.w3.org/TR/wai-aria-practices/examples/button/button.html)

The behavior of the "Mute" button here is interesting. If you tab to the Mute button, then press and hold the Space key, there is a brief delay, then the button activates (fires) repeatedly. This does not match the behavior that we've seen for the Space key - we've seen activation on keydown, with seemingly no way to accomplish fireOnHold.

The links to source code are also interesting. In button.js, they add event listeners for click and keydown to each button. Why?

Question: Why is the activation behavior different in this example? Is there something we can apply? (EDIT: See also the commits for example fixes in w3c/aria-practices#610.)

@pixelzoom
Copy link
Contributor

pixelzoom commented Mar 3, 2019

Here's a bug report related to the difference between Enter and Space. It indicates that the button examples in #939 (comment) are buggy, and the ARIA design pattern is incompletely specified.

The bug report is w3c/aria-practices#610:

The synthetic click event that happens on native elements occurs on keydown for Enter and keyup for Space, but the button pattern doesn't describe this behavior and the example does not exhibit it.

I found this bug report by clicking the "Related Issues" link for the ARIA role=button examples at https://www.w3.org/TR/wai-aria-practices/examples/button/button.html. Note that this issue is in repository w3c/aria-practices (ARIA Practices). It was verified to be a bug, it was fixed, and the issue was closed on 10/12/2018.

Edit: Note that this bug report is the first place where I've found evidence that the Enter and Space keys are expected to behave differently.
Question: Should we contact someone from W3C ARIA to find out why Enter and Space are different, if it's a standard that shouldn't be changed, etc.?

@pixelzoom pixelzoom changed the title How to treat Space vs Enter in a11y clicking How to treat Space vs Enter for buttons Mar 3, 2019
@pixelzoom pixelzoom changed the title How to treat Space vs Enter for buttons How to handle Space vs Enter for buttons Mar 3, 2019
@terracoda
Copy link

Great investigation and questions @pixelzoom. And glad you found the latest version of the button examples. The first link was to a "WD" or "working draft". In the latest version, on the Mute toggle button, the Space key fires/is activated on release and the Enter key fires/activates repeatedly which seems more typical, though still unexplained by the standards documentation.

@jessegreenberg and I investigated many types of button in our early investigations for BASE's custom "drag & gab" interaction, but for other reasons. We know a lot more now - both about users and about the HTML and ARIA specifications.

Exploring how activation can be customized, understanding the fullest potential of the click event, and exploring further possibilities available through the aria-pressed attribute are all very worthy discussion topics.

Looking forward to our discussion.

@samreid
Copy link
Member

samreid commented Mar 7, 2019

@jessegreenberg or @zepumph can you please summarize the discussion from Monday, and point out the next steps for this issue? Does it still need to be discussed at dev meeting?

@jessegreenberg
Copy link
Contributor

jessegreenberg commented Mar 7, 2019

During discussion on 3/4/19 we reviewed why we are encountering this issue and potential solutions. We discussed how scenery/simulations would behave if we proceed with changes described in #945. No major concerns with this came up during the meeting.

An alternative proposed during the meeting was to ignore "press and hold" and "fire on down" interaction for alternative input and just fire buttons on click events as they hit the browser natively (which is what we are doing now). @jessegreenberg thinks it is still worth exploring #945 since this will provide us with "press and hold" and "fire on down" buttons for alternative input, while still responding to single click events when they are received from an assistive device. During the meeting it was mentioned that the downside of this is that behavior will change when an AT is in use and therefore increase the cost of development and testing.

Here are the next steps:
After the meeting @zepumph mentioned that he encountered different results than I had reported in #939 (comment), we should understand why that is the case.

@pixelzoom identified a number of resources and questions in #939 (comment) #939 (comment) and #939 (comment), those should be reviewed before more work is done.

After doing those things we can decide whether or not to proceed with #945.

@terracoda
Copy link

@jessegreenberg, I also shared with you, @pixelzoom and @zepumph comments from the WAI ARIA interest group which included a mark-up idea that we have not yet explored, nesting a button element within a parent element with role=application.

<div role="application">
  <button>Squeeze Eye-dropper</button> 
</div> 

This mark-up could potentially be useful for the "press and hold" and "fire on down" buttons once we get them for alternative input.

Just adding it, since it is related to the issue.

@jessegreenberg
Copy link
Contributor

Thanks for collecting resources and questions @pixelzoom. Some of this we have already considered but all
of it is worth looking into.

I am reviewing the questions and links listed in #939 (comment), #939 (comment), #939 (comment) and #939 (comment)

Question: Can we customize button activation behavior?

Not to my knowledge. https://www.w3.org/TR/html5/editing.html#activation spec is for the user agent (browser), I don't see anything there usable by web developers.

Question: Have we investigated how button activation changes depending on the value of the type attribute?

The type attribute controls the behavior of the button with respect to a containing <form> element. It doesn't have an impact on the DOM events. I created https://jsfiddle.net/ne2xrhyp/1/ to verify, this example has submit, reset, and button buttons. Event behavior is the same for all.

Question: Can we use the aria-pressed attribute to provide more context for interpreting click events? (EDIT: After further reading, using aria-pressed for non-toggle buttons doesn't sound like a good idea.)

+1 to the edit. But I also verified that aria-pressed has no impact on events when an AT is in use.

The steps involved in “run synthetic click activation steps” are defined in the Activation section of the spec, mentioned above and at https://www.w3.org/TR/html5/editing.html#activation. These steps appear to be customizable.
Question: Do any of the click event fields provide us with useful information?
Question: Can synthesis of the click event be customized?

These are steps for the user agent. The fields available for web developers are listed in MouseEvent(because click uses the MouseEvent interface even though it is commonly triggered with keyboards and assistive tech).

ARIA examples for role=button are at...
In button.js, they add event listeners for click and keydown to each button. Why?
Question: Why is the activation behavior different in this example? Is there something we can apply?

It is mentioned in https://www.w3.org/TR/2016/WD-wai-aria-practices-1.1-20160317/examples/button/button.html# that keydown is added to handle keyboard support and click is added to handle mouse clicks and screen readers. @terracoda and I tried something similar in #939 (comment). It could be a way to get enter and spacebar to behave the same, but it has the same problem with AT in that it won't support the options of PushButtonModel.

Question: Should we contact someone from W3C ARIA to find out why Enter and Space are different, if it's a standard that shouldn't be changed, etc.?

Yes, we could do that. We happen to know the author of that issue who is a member of the ARIA WG. Differences between enter and spacebar go beyond buttons and the web. For instance, checkboxes only activate with spacebar, they don't respond to enter. I just verified that was true in a native Windows app.
image

@jessegreenberg
Copy link
Contributor

Actually, I had forgotten that @terracoda already reached out to the ARIA group about this. https://lists.w3.org/Archives/Public/w3c-wai-ig/2019JanMar/0086.html

@jessegreenberg
Copy link
Contributor

No matter whata we do, somewhere in button code we will need to change the markup for the button so that it looks like

<div role="application">
  <button>BUTTON</button>
</div>

If we don't go with #945, somewhere in button code we will also have to opt out of click listeners. We could have an option in PressListener like activateWithKeyboardEvent that disables the click listeners and uses keyup and keydown listeners instead.

If we do this, it will make button code a little more complicated, keyboard use without a screen reader will generally not support PushButtonModel options. But we avoid doing something tricky and PhET specific for a11y in scenery. And we avoid adding differences in sim behavior when a screen reader is enabled vs disabled.

I think we should just do that. This will also set us up for switching to #945 strategy if we need to later, but avoids trickiness for now.

@zepumph can we talk at tomorrows dev meeting to finalize?

@jessegreenberg
Copy link
Contributor

Notes from 4/8/19 discussion:

During discussion on 4/8/19, @samreid suggested that rather than having some of our buttons use use unique markup and input handling that we modify the user interface (both visual and PDOM) to support different modes of interaction. For instance, for the StepButton we could also have a "slow motion" button that changes the behavior of step to work better with single click activations. However, it is unclear how this would work because the step button will still respond to click events at the interval that the assistive device sends events to the browser. And modifying the UI will be more time intensive.

By keeping our current system, we get the semantic button interaction that has been tested with users and we know works well. We don't have to change our input system for a11y or doing anything that is PhET specific. For specific buttons, we can support PushButtonModel options doing the following:

  • Some buttons will have different markup that looks like
  <div role="application">
    <button>BUTTON</button>
  </div>
  • And PressListener will be modified to optionally support keydown and keyup events rather than click events.

If in user interviews we determine that this is too confusing for users, we will be in an OK position to
change approaches again at that point.

@zepumph recommended that these decisions should be documented in style guide document files (like PushButton.md) for review from relevant people in the future.

@jessegreenberg
Copy link
Contributor

jessegreenberg commented Apr 8, 2019

@samreid also provided these notes from discussion:

We additionally discussed these examples:

  • Changing the pDOM elements for MomentaryPushButtonModel buttons to toggle buttons, so on the first click, the button is pressed and on the second click, the button is released.
  • Breaking out the “Step” button with 2 mode of interaction (press once to step once vs press and hold to go in slow motion), to two buttons each with one mode of interaction (one button that steps once when pressed once and another button or radio button for slow motion).

We concluded that <div role="application"> can be used to get things working “out of the box” but that should be “opt in” and for components that use that strategy, we should consider other alternate patterns during the a11y design process, because “press and hold” is (a) not necessarily something all users can do and (b) an unconventional accessibility pattern compared to standard html components.

@terracoda
Copy link

We concluded that

can be used to get things working “out of the box” but that should be “opt in” and for components that use that strategy, we should consider other alternate patterns during the a11y design process, because “press and hold” is (a) not necessarily something all users can do and (b) an unconventional accessibility pattern compared to standard html components.

I agree that <div role="application"> should be an opt-in option. <div role="application"> is meant for custom interactions. In interviews thus far (BASE, Friction, Faraday's Law) this role has not yet been understandable or easily operable by users. Explicit guiding instructions are always needed and these instructions vary by platform (e.g., keyboard, touch).

I also agree with (a) and (b) in the above comment.

We need to tread very carefully with <div role="application">.

@jessegreenberg
Copy link
Contributor

Some buttons will have different markup that uses role="application"
And PressListener will be modified to optionally support keydown and keyup events rather than click events.

This means that we are proceeding with our current input system for catching click events and we will add support for keydown keyup in PressListener when we require them. This issue no longer needs to block publication.

@jessegreenberg
Copy link
Contributor

The work described in #939 (comment) has been moved to #1117. Closing this issue.

@samreid
Copy link
Member

samreid commented Jul 3, 2021

Reopening based on the TODO in the code:

   * TODO: This may change after https://github.com/phetsims/scenery/issues/939 is done, at which point
   * `click` should likely be replaced by `keydown` and `keyup` listeners.

@samreid samreid reopened this Jul 3, 2021
@jessegreenberg
Copy link
Contributor

Thanks, I updated the link to point to the new issue referenced in #939 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants