Skip to content

Commit 2400071

Browse files
Merge pull request #3787 from gcoayla/portal-tab-loop
fix: fix accessibility issues adding tab loop to datepicker with portal
2 parents 0bfd40c + 3e9dba5 commit 2400071

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

src/index.jsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
DEFAULT_YEAR_ITEM_NUMBER,
4242
isSameDay,
4343
} from "./date_utils";
44+
import TabLoop from "./tab_loop";
4445
import onClickOutside from "react-onclickoutside";
4546

4647
export { default as CalendarContainer } from "./calendar_container";
@@ -709,7 +710,6 @@ export default class DatePicker extends React.Component {
709710
}
710711
} else if (eventKey === "Escape") {
711712
event.preventDefault();
712-
713713
this.setOpen(false);
714714
}
715715

@@ -719,6 +719,25 @@ export default class DatePicker extends React.Component {
719719
}
720720
};
721721

722+
onPortalKeyDown = (event) => {
723+
const eventKey = event.key;
724+
if (eventKey === "Escape") {
725+
event.preventDefault();
726+
this.setState(
727+
{
728+
preventFocus: true,
729+
},
730+
() => {
731+
this.setOpen(false);
732+
setTimeout(() => {
733+
this.setFocus();
734+
this.setState({ preventFocus: false });
735+
});
736+
}
737+
);
738+
}
739+
};
740+
722741
// keyDown events passed down to day.jsx
723742
onDayKeyDown = (event) => {
724743
this.props.onKeyDown(event);
@@ -1071,7 +1090,15 @@ export default class DatePicker extends React.Component {
10711090

10721091
if (this.props.withPortal) {
10731092
let portalContainer = this.state.open ? (
1074-
<div className="react-datepicker__portal">{calendar}</div>
1093+
<TabLoop enableTabLoop={this.props.enableTabLoop}>
1094+
<div
1095+
className="react-datepicker__portal"
1096+
tabIndex={-1}
1097+
onKeyDown={this.onPortalKeyDown}
1098+
>
1099+
{calendar}
1100+
</div>
1101+
</TabLoop>
10751102
) : null;
10761103

10771104
if (this.state.open && this.props.portalId) {

test/datepicker_test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,33 @@ describe("DatePicker", () => {
583583
expect(datePicker.calendar).to.exist;
584584
});
585585

586+
it("should render Calendar in portal when withPortal is set and should close on Escape key when focus is on header", () => {
587+
var datePicker = TestUtils.renderIntoDocument(
588+
<DatePicker withPortal portalId="portal-id-dom-test" />
589+
);
590+
var dateInput = datePicker.input;
591+
TestUtils.Simulate.focus(ReactDOM.findDOMNode(dateInput));
592+
593+
expect(function () {
594+
TestUtils.findRenderedDOMComponentWithClass(
595+
datePicker,
596+
"react-datepicker__portal"
597+
);
598+
}).to.not.throw();
599+
expect(datePicker.calendar).to.exist;
600+
601+
var header = TestUtils.scryRenderedDOMComponentsWithClass(
602+
datePicker,
603+
"react-datepicker__current-month"
604+
)[0];
605+
606+
TestUtils.Simulate.click(ReactDOM.findDOMNode(header));
607+
608+
TestUtils.Simulate.keyDown(ReactDOM.findDOMNode(header), getKey("Escape"));
609+
610+
expect(datePicker.calendar).to.not.exist;
611+
});
612+
586613
it("should not render Calendar when withPortal is set and no focus is given to input", () => {
587614
var datePicker = TestUtils.renderIntoDocument(<DatePicker withPortal />);
588615

0 commit comments

Comments
 (0)