diff --git a/src/components/forms/ComboBox/ComboBox.test.tsx b/src/components/forms/ComboBox/ComboBox.test.tsx
index d709a6da40..c5b69e0a60 100644
--- a/src/components/forms/ComboBox/ComboBox.test.tsx
+++ b/src/components/forms/ComboBox/ComboBox.test.tsx
@@ -482,6 +482,25 @@ describe('ComboBox component', () => {
fireEvent.blur(getByTestId('combo-box-clear-button'))
expect(getByTestId('combo-box-input')).toHaveFocus()
})
+
+ it('focuses the input after clearing when the when FocusMode is None', () => {
+ const { getByTestId } = render(
+ <>
+
+
+ >
+ )
+
+ userEvent.type(getByTestId('combo-box-input'), 'b')
+ userEvent.click(getByTestId('outside'))
+ userEvent.click(getByTestId('combo-box-clear-button'))
+ expect(getByTestId('combo-box-input')).toHaveFocus()
+ })
})
it('clears input value and closes list when an incomplete item is remaining on blur', () => {
@@ -1058,6 +1077,24 @@ describe('ComboBox component', () => {
'usa-combo-box__list-option--focused'
)
})
+
+ it('clears focus when clicking outside of the component', () => {
+ const { getByTestId } = render(
+ <>
+
+
+ >
+ )
+
+ userEvent.click(getByTestId('combo-box-toggle'))
+ userEvent.click(getByTestId('outside'))
+ expect(getByTestId('combo-box-input')).not.toHaveFocus()
+ })
})
describe('accessibility and internationalization', () => {
diff --git a/src/components/forms/ComboBox/ComboBox.tsx b/src/components/forms/ComboBox/ComboBox.tsx
index d3b7c4e1b7..a40eac39e5 100644
--- a/src/components/forms/ComboBox/ComboBox.tsx
+++ b/src/components/forms/ComboBox/ComboBox.tsx
@@ -145,16 +145,13 @@ export const ComboBox = (props: ComboBoxProps): React.ReactElement => {
}
const handleInputBlur = (event: FocusEvent): void => {
- const { target: elementLosingFocus, relatedTarget: newTarget } = event
+ const { relatedTarget: newTarget } = event
const newTargetIsOutside =
!newTarget ||
- (newTarget instanceof Node &&
- !containerRef.current?.contains(elementLosingFocus))
+ (newTarget instanceof Node && !containerRef.current?.contains(newTarget))
- if (state.selectedOption?.value) {
- if (newTargetIsOutside) dispatch({ type: ActionTypes.CLOSE_LIST })
- } else if (newTargetIsOutside) {
- dispatch({ type: ActionTypes.CLEAR })
+ if (newTargetIsOutside) {
+ dispatch({ type: ActionTypes.BLUR })
}
}
@@ -203,7 +200,7 @@ export const ComboBox = (props: ComboBoxProps): React.ReactElement => {
!newTarget ||
(newTarget instanceof Node && !containerRef.current?.contains(newTarget))
) {
- dispatch({ type: ActionTypes.CLOSE_LIST })
+ dispatch({ type: ActionTypes.BLUR })
}
}
diff --git a/src/components/forms/ComboBox/useCombobox.ts b/src/components/forms/ComboBox/useCombobox.ts
index 743ab9a6f3..c436e0ed19 100644
--- a/src/components/forms/ComboBox/useCombobox.ts
+++ b/src/components/forms/ComboBox/useCombobox.ts
@@ -9,6 +9,7 @@ export enum ActionTypes {
CLOSE_LIST,
FOCUS_OPTION,
UPDATE_FILTER,
+ BLUR,
}
export type Action =
@@ -33,7 +34,9 @@ export type Action =
type: ActionTypes.UPDATE_FILTER
value: string
}
-
+ | {
+ type: ActionTypes.BLUR
+ }
export interface State {
isOpen: boolean
selectedOption?: ComboBoxOption
@@ -124,11 +127,29 @@ export const useCombobox = (
...state,
inputValue: '',
isOpen: false,
+ focusMode: FocusMode.Input,
selectedOption: undefined,
filter: undefined,
filteredOptions: optionsList.filter(isPartialMatch('')),
}
+ case ActionTypes.BLUR: {
+ const newState = {
+ ...state,
+ isOpen: false,
+ focusMode: FocusMode.None,
+ focusedOption: undefined,
+ }
+ if (state.filteredOptions.length === 0) {
+ newState.filteredOptions = optionsList.filter(isPartialMatch(''))
+ }
+
+ if (!state.selectedOption) {
+ newState.inputValue = ''
+ }
+
+ return newState
+ }
default:
throw new Error()
}