diff --git a/packages/react-aria-components/test/ListBox.test.js b/packages/react-aria-components/test/ListBox.test.js
index 026eea5d36a..ef72826d104 100644
--- a/packages/react-aria-components/test/ListBox.test.js
+++ b/packages/react-aria-components/test/ListBox.test.js
@@ -2523,6 +2523,39 @@ describe('keyboard modifier keys', () => {
expect(document.activeElement).toBe(options[1]);
});
+ it('does not activate an element focused during selection with Enter', async () => {
+ let onClick = jest.fn();
+ let triggerRef = React.createRef();
+ let {getByRole} = render(
+ <>
+
+ {
+ // oxlint-disable-next-line rsp-rules/act-events-test
+ triggerRef.current.focus();
+ }}>
+ Cat
+ Dog
+
+ >
+ );
+
+ let options = within(getByRole('listbox')).getAllByRole('option');
+ act(() => options[0].focus());
+
+ // Selection moves focus to the trigger during keydown. Unless Enter's default is
+ // prevented, the browser dispatches the activation click to the newly focused
+ // element.
+ await user.keyboard('{Enter}');
+
+ expect(triggerRef.current).toHaveFocus();
+ expect(onClick).not.toHaveBeenCalled();
+ });
+
describe('multiple selection, replace behavior', () => {
it('replaces selection as focus moves with arrow keys', async () => {
let onSelectionChange = jest.fn();
diff --git a/packages/react-aria/src/interactions/usePress.ts b/packages/react-aria/src/interactions/usePress.ts
index 517c8019b90..8b847ac1848 100644
--- a/packages/react-aria/src/interactions/usePress.ts
+++ b/packages/react-aria/src/interactions/usePress.ts
@@ -391,7 +391,7 @@ export function usePress(props: PressHookProps): PressResult {
isValidKeyboardEvent(e.nativeEvent, e.currentTarget as Element) &&
nodeContains(e.currentTarget as Element, getEventTarget(e) as Element)
) {
- if (shouldPreventDefaultKeyboard(getEventTarget(e) as Element, e.key)) {
+ if (shouldPreventDefaultKeyboard(getEventTarget(e) as Element, e)) {
e.preventDefault();
}
@@ -497,7 +497,7 @@ export function usePress(props: PressHookProps): PressResult {
let onKeyUp = (e: KeyboardEvent) => {
if (state.isPressed && state.target && isValidKeyboardEvent(e, state.target)) {
- if (shouldPreventDefaultKeyboard(getEventTarget(e) as Element, e.key)) {
+ if (shouldPreventDefaultKeyboard(getEventTarget(e) as Element, e)) {
e.preventDefault();
}
@@ -1161,9 +1161,13 @@ function shouldPreventDefaultUp(target: Element) {
return true;
}
-function shouldPreventDefaultKeyboard(target: Element, key: string) {
- // Don't prevent the contextmenu shortcut on mac.
- if (isMac() && key === 'Enter') {
+function shouldPreventDefaultKeyboard(
+ target: Element,
+ event: Pick
+) {
+ let {key} = event;
+ // Don't prevent the contextmenu shortcut (Control + Enter) on mac.
+ if (isMac() && key === 'Enter' && event.ctrlKey) {
return false;
}
diff --git a/packages/react-aria/test/interactions/usePress.test.js b/packages/react-aria/test/interactions/usePress.test.js
index 1f944d2d9ca..e54662e0f27 100644
--- a/packages/react-aria/test/interactions/usePress.test.js
+++ b/packages/react-aria/test/interactions/usePress.test.js
@@ -3173,6 +3173,29 @@ describe('usePress', function () {
]);
});
+ it('should prevent default on Enter on macOS', function () {
+ let {getByText} = render();
+ using spy = jest.spyOn(window.navigator, 'platform', 'get').mockImplementation(() => 'Mac');
+
+ let el = getByText('test');
+ let allowDefault = fireEvent.keyDown(el, {key: 'Enter'});
+ expect(allowDefault).toBe(false);
+ allowDefault = fireEvent.keyUp(el, {key: 'Enter'});
+ expect(allowDefault).toBe(false);
+ spy.mockRestore();
+ });
+
+ it('should not prevent default on Control + Enter on macOS so the context menu can open', function () {
+ let {getByText} = render();
+ using spy = jest.spyOn(window.navigator, 'platform', 'get').mockImplementation(() => 'Mac');
+
+ let el = getByText('test');
+ let allowDefault = fireEvent.keyDown(el, {key: 'Enter', ctrlKey: true});
+ expect(allowDefault).toBe(true);
+ fireEvent.keyUp(el, {key: 'Enter', ctrlKey: true});
+ spy.mockRestore();
+ });
+
it('should handle when focus moves between keydown and keyup', function () {
let events = [];
let addEvent = e => events.push(e);