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

fix(3635): a11y - Sets focus to input on select #4285

Merged
merged 1 commit into from
Oct 3, 2023

Conversation

justinseiter
Copy link

Fixes: #3635 : Accessibility issue - when date picker closes focus does not return on input

Issue

When using the Escape or Enter keys as well as after selection with pointer, focus did not return to input.

Accessibility guidelines suggest that in these instances focus should return to the input.

What were the specific changes made?

  • Adds a sendFocusBackToInput method for handling returning focus. There were already two separate (nearly identical) implementations to handle this within handleSelect and onPopperKeydown. The sendFocusBackToInput is simply an abstraction to facilitate reuse in those instances as well as several others.
  • Adds tests around possible consumer implementations.

Additional notes/context

This work makes considerations not only for default implementations but as well as:

  • isClearable - Clicking clear now returns focus to input
  • customInput - This one Just Works ™️ as long as implemented as outlined in docs (ie with forwardRef)
  • shouldCloseOnSelect - Don't hide calendar on date selection means we'll keep focus within picker
  • disabledKeyboardNavigation- Pointer only
  • showTimeSelect - When this prop is enabled the picker currently closes once a time is selected. This work just makes sure that focus only returns on that event and not on date selection.
  • inline - Focus remains on picker
  • withPortal - Again, Just works ™️ thanks to previous contributors. :)
  • Pressing Escape while in the input field - If picker was open and focus was on input, pressing Escape would send focus to body. Now returns to input.
CleanShot.2023-09-29.at.12.07.25.mp4

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was sent to the PullRequest network.


@justinseiter you can click here to see the review status or cancel the code review job.

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PullRequest Breakdown

Reviewable lines of change

+ 148
- 27

69% JavaScript (tests)
31% JavaScript

Type of change

Fix - These changes are likely to be fixing a bug or issue.

* Adds sendFocusBackToInput method for handling returning focus.
* Adds tests around possible consumer implementations.
@codecov
Copy link

codecov bot commented Oct 2, 2023

Codecov Report

Merging #4285 (1ffa8b6) into main (68c8914) will increase coverage by 0.17%.
Report is 12 commits behind head on main.
The diff coverage is 100.00%.

❗ Current head 1ffa8b6 differs from pull request most recent head 83afadf. Consider uploading reports for the commit 83afadf to get more accurate results

@@            Coverage Diff             @@
##             main    #4285      +/-   ##
==========================================
+ Coverage   96.34%   96.52%   +0.17%     
==========================================
  Files          25       25              
  Lines        2352     2358       +6     
  Branches      958      962       +4     
==========================================
+ Hits         2266     2276      +10     
+ Misses         86       82       -4     
Files Coverage Δ
src/index.jsx 94.24% <100.00%> (+0.47%) ⬆️
src/inputTime.jsx 96.15% <100.00%> (+4.48%) ⬆️

... and 1 file with indirect coverage changes

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this feature should successfully improve accessibility as described. I like that the tests were expanded so much for this. I just flagged a few things that our automation caught for future work since some things have been deprecated that affect the tests.

Image of Dallas Dallas


Reviewed with ❤️ by PullRequest

@@ -97,7 +97,7 @@ describe("DatePicker", () => {
expect(datePicker.state.open).toBe(false);
});

it("should close the popper and return focus to the date input.", (done) => {
it("should close the popper and return focus to the date input on Escape.", (done) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice clarification here on an existing test

◽ Compliment

Image of Dallas Dallas

// Date Picker Dialog | Date Grid | Enter | Closes the dialog and returns focus to the Choose Date button.
var div = document.createElement("div");
document.body.appendChild(div);
var datePicker = ReactDOM.render(<DatePicker />, div);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISSUE: react/no-render-return-value (Severity: Medium)
Do not depend on the return value from ReactDOM.render

Remediation:
Automation Result: react/no-render-return-value Do not depend on the return value from ReactDOM.render
It looks like these tests will need to be updated at some point. This link gives information about how this is legacy and what to do instead.

The existing test has this same code. It doesn't necessarily need to be fixed in this PR.

🤖 powered by PullRequest Automation 👋 verified by Dallas

done();
});
});

it("should hide the calendar when the pressing Shift + Tab in the date input", () => {
var datePicker = TestUtils.renderIntoDocument(
<DatePicker onBlur={onBlurSpy} />,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISSUE: no-use-before-define (Severity: Medium)
'onBlurSpy' was used before it was defined.

Remediation:
Automation Result: no-use-before-define 'onBlurSpy' was used before it was defined.
This isn't actually in the changed code, but it looks like things are out of order here and that onBlurSpy is defined 2 lines below this. Does this test work as expected?

🤖 powered by PullRequest Automation 👋 verified by Dallas

it("should return focus to input once time is selected", (done) => {
document.body.appendChild(div); // So we can check the dom later for activeElement
renderDatePicker("February 28, 2018 4:43 PM");
const dateInput = ReactDOM.findDOMNode(datePicker.input);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISSUE: react/no-find-dom-node (Severity: Medium)
Do not use findDOMNode. It doesn’t work with function components and is deprecated in StrictMode. See https://reactjs.org/docs/react-dom.html#finddomnode

Remediation:
Automation Result: react/no-find-dom-node Do not use findDOMNode. It doesn’t work with function components and is deprecated in StrictMode. See https://reactjs.org/docs/react-dom.html#finddomnode

It looks like this has been deprecated and should be updated soon. It is being used many times in this file, so it should probably be its own PR later.

🤖 powered by PullRequest Automation 👋 verified by Dallas

Copy link

@pullrequest pullrequest bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR looks quite good for addressing the a11y problems outlined in the original issue. It's great to have the behavior for returning focus consolidated into one place and invoked where necessary, compared to the previous approach.

Thanks for such an excellent write-up as well.

I see the another reviewer already left some comments, and I don't see any further issues.

Nice work!

Image of Ryan Ryan


Reviewed with ❤️ by PullRequest

@@ -123,6 +123,53 @@ describe("DatePicker", () => {
});
});

it("should close the popper and return focus to the date input on Enter.", (done) => {
// https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/datepicker-dialog.html
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding in the relevant documentation here is really useful—thanks!

◽ Compliment

Image of Ryan Ryan

var dateInput = div.querySelector("input");
TestUtils.Simulate.focus(dateInput);

// user may tab or arrow down to the current day (or some other element in the popper)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is also really great that you're walking us through each step of the test in detail. This helps a lot with readability and future maintainability.

◽ Compliment

Image of Ryan Ryan

Copy link
Member

@martijnrusschen martijnrusschen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is looking great.

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

Successfully merging this pull request may close these issues.

Accessibility issue - when date picker closes focus does not return on input
2 participants