Skip to content

Commit c036179

Browse files
committed
feat(Select): default arrow key handling to focus items
1 parent f19a7a5 commit c036179

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

packages/react-core/src/components/Select/Select.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export interface SelectProps extends MenuProps, OUIAProps {
6262
onOpenChange?: (isOpen: boolean) => void;
6363
/** Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable. */
6464
onOpenChangeKeys?: string[];
65+
/** Custom callback to override the default behaviour when pressing up/down arrows. Defaults to navigating through the menu items (with focus on them). */
66+
onArrowUpDownKeyPress?: (event: KeyboardEvent) => void;
6567
/** Indicates if the select should be without the outer box-shadow */
6668
isPlain?: boolean;
6769
/** @hide Forwarded ref */
@@ -95,6 +97,7 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
9597
shouldFocusFirstItemOnOpen = false,
9698
onOpenChange,
9799
onOpenChangeKeys = ['Escape', 'Tab'],
100+
onArrowUpDownKeyPress,
98101
isPlain,
99102
innerRef,
100103
zIndex = 9999,
@@ -131,6 +134,18 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
131134
}, [isOpen]);
132135

133136
React.useEffect(() => {
137+
const onArrowUpDownKeyPressDefault = (event: KeyboardEvent) => {
138+
event.preventDefault();
139+
140+
const firstItemSelector = 'li button:not(:disabled),li input:not(:disabled)';
141+
const lastItemSelector = 'li:last-child button:not(:disabled),li:last-child input:not(:disabled)';
142+
143+
const elementToFocus = menuRef?.current?.querySelector(
144+
event.key === 'ArrowDown' ? firstItemSelector : lastItemSelector
145+
);
146+
elementToFocus && (elementToFocus as HTMLElement).focus();
147+
};
148+
134149
const handleMenuKeys = (event: KeyboardEvent) => {
135150
// Close the menu on tab or escape if onOpenChange is provided
136151
if (
@@ -144,6 +159,10 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
144159
toggleRef.current?.focus();
145160
}
146161
}
162+
163+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
164+
onArrowUpDownKeyPress ? onArrowUpDownKeyPress(event) : onArrowUpDownKeyPressDefault(event);
165+
}
147166
};
148167

149168
const handleClick = (event: MouseEvent) => {

packages/react-core/src/components/Select/examples/SelectTypeahead.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ export const SelectTypeahead: React.FunctionComponent = () => {
243243
onOpenChange={(isOpen) => {
244244
!isOpen && closeMenu();
245245
}}
246+
onArrowUpDownKeyPress={(_event) => {}}
246247
toggle={toggle}
247248
shouldFocusFirstItemOnOpen={false}
248249
>

packages/react-templates/src/components/Select/TypeaheadSelect.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ export const TypeaheadSelectBase: React.FunctionComponent<TypeaheadSelectProps>
360360
onOpenChange={(isOpen) => {
361361
!isOpen && closeMenu();
362362
}}
363+
onArrowUpDownKeyPress={(_event) => {}}
363364
toggle={toggle}
364365
shouldFocusFirstItemOnOpen={false}
365366
ref={innerRef}

0 commit comments

Comments
 (0)