diff --git a/src/index.tsx b/src/index.tsx index 419a316f8..e6a9cd3d7 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -717,10 +717,13 @@ export class DatePicker extends Component { }; handleCalendarClickOutside = (event: MouseEvent) => { - if (!this.props.inline) { + // Call user's onClickOutside first, allowing them to call preventDefault() + this.props.onClickOutside?.(event); + + // Only close if not prevented and not inline + if (!this.props.inline && !event.defaultPrevented) { this.setOpen(false); } - this.props.onClickOutside?.(event); if (this.props.withPortal) { event.preventDefault(); } diff --git a/src/test/datepicker_test.test.tsx b/src/test/datepicker_test.test.tsx index 65f61e47e..32cbb423c 100644 --- a/src/test/datepicker_test.test.tsx +++ b/src/test/datepicker_test.test.tsx @@ -2793,6 +2793,28 @@ describe("DatePicker", () => { expect(onClickOutsideSpy).toHaveBeenCalledTimes(1); }); + it("should not close date picker when onClickOutside calls preventDefault", () => { + const onClickOutside = (event: MouseEvent) => { + event.preventDefault(); + }; + const { container } = render( +
+ outside + +
, + ); + + const input = safeQuerySelector(container, "input"); + fireEvent.focus(input); + expect(container.querySelector(".react-datepicker")).not.toBeNull(); + + const outsideElement = safeQuerySelector(container, ".outsideElement"); + fireEvent.mouseDown(outsideElement); + + // Calendar should remain open because preventDefault was called + expect(container.querySelector(".react-datepicker")).not.toBeNull(); + }); + it("should not close date picker on input click", () => { const onClickOutsideSpy = jest.fn(); const { container } = render(