diff --git a/packages/mui-base/src/ListboxUnstyled/useListbox.test.tsx b/packages/mui-base/src/ListboxUnstyled/useListbox.test.tsx
index 1b510ccf881553..f3109b79987bb1 100644
--- a/packages/mui-base/src/ListboxUnstyled/useListbox.test.tsx
+++ b/packages/mui-base/src/ListboxUnstyled/useListbox.test.tsx
@@ -1,7 +1,8 @@
import * as React from 'react';
-import { useListbox } from '@mui/base/ListboxUnstyled';
import { expect } from 'chai';
-import { createRenderer } from 'test/utils';
+import { SinonSpy, spy } from 'sinon';
+import { useListbox } from '@mui/base/ListboxUnstyled';
+import { createRenderer, createEvent, fireEvent } from 'test/utils';
describe('useListbox', () => {
const { render } = createRenderer();
@@ -56,4 +57,72 @@ describe('useListbox', () => {
expect(listboxes[0].id).not.to.equal(listboxes[1].id);
});
});
+
+ describe('preventing default behavior on keyDown', () => {
+ ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown', 'Enter', ' '].forEach((key) =>
+ it(`prevents default behavior when ${key} is pressed in activeDescendant focus management mode`, () => {
+ const Listbox = () => {
+ const { getRootProps } = useListbox({ options: [], focusManagement: 'activeDescendant' });
+ return
;
+ };
+
+ const { getByRole } = render();
+ const listbox = getByRole('listbox');
+ listbox.focus();
+
+ const event = createEvent.keyDown(listbox, {
+ key,
+ });
+
+ event.preventDefault = spy();
+ fireEvent(listbox, event);
+
+ expect((event.preventDefault as SinonSpy).calledOnce).to.equal(true);
+ }),
+ );
+
+ ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].forEach((key) =>
+ it(`prevents default behavior when ${key} is pressed in DOM focus management mode`, () => {
+ const Listbox = () => {
+ const { getRootProps } = useListbox({ options: [], focusManagement: 'DOM' });
+ return ;
+ };
+
+ const { getByRole } = render();
+ const listbox = getByRole('listbox');
+ listbox.focus();
+
+ const event = createEvent.keyDown(listbox, {
+ key,
+ });
+
+ event.preventDefault = spy();
+ fireEvent(listbox, event);
+
+ expect((event.preventDefault as SinonSpy).calledOnce).to.equal(true);
+ }),
+ );
+
+ ['Enter', ' '].forEach((key) =>
+ it(`does not prevent default behavior when ${key} is pressed in DOM focus management mode`, () => {
+ const Listbox = () => {
+ const { getRootProps } = useListbox({ options: [], focusManagement: 'DOM' });
+ return ;
+ };
+
+ const { getByRole } = render();
+ const listbox = getByRole('listbox');
+ listbox.focus();
+
+ const event = createEvent.keyDown(listbox, {
+ key,
+ });
+
+ event.preventDefault = spy();
+ fireEvent(listbox, event);
+
+ expect((event.preventDefault as SinonSpy).notCalled).to.equal(true);
+ }),
+ );
+ });
});
diff --git a/packages/mui-base/src/ListboxUnstyled/useListbox.ts b/packages/mui-base/src/ListboxUnstyled/useListbox.ts
index f6d769f103c335..40a96391b717ab 100644
--- a/packages/mui-base/src/ListboxUnstyled/useListbox.ts
+++ b/packages/mui-base/src/ListboxUnstyled/useListbox.ts
@@ -160,16 +160,15 @@ export default function useListbox(props: UseListboxParameters
return;
}
- const keysToPreventDefault = [
- ' ',
- 'Enter',
- 'ArrowUp',
- 'ArrowDown',
- 'Home',
- 'End',
- 'PageUp',
- 'PageDown',
- ];
+ const keysToPreventDefault = ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'];
+
+ if (focusManagement === 'activeDescendant') {
+ // When the child element is focused using the activeDescendant attribute,
+ // the listbox handles keyboard events on its behalf.
+ // We have to `preventDefault()` is this case to prevent the browser from
+ // scrolling the view when space is pressed or submitting forms when enter is pressed.
+ keysToPreventDefault.push(' ', 'Enter');
+ }
if (keysToPreventDefault.includes(event.key)) {
event.preventDefault();