Skip to content

Commit 05f6a30

Browse files
authored
fix: ComboBox correctly resets to defaultSelectedKey (#9129)
1 parent 1cbf47d commit 05f6a30

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

packages/@react-aria/combobox/src/useComboBox.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {AriaComboBoxProps} from '@react-types/combobox';
1616
import {ariaHideOutside} from '@react-aria/overlays';
1717
import {AriaListBoxOptions, getItemId, listData} from '@react-aria/listbox';
1818
import {BaseEvent, DOMAttributes, KeyboardDelegate, LayoutDelegate, PressEvent, RefObject, RouterOptions, ValidationResult} from '@react-types/shared';
19-
import {chain, getActiveElement, getOwnerDocument, isAppleDevice, mergeProps, useEvent, useLabels, useRouter, useUpdateEffect} from '@react-aria/utils';
19+
import {chain, getActiveElement, getOwnerDocument, isAppleDevice, mergeProps, useEvent, useFormReset, useLabels, useRouter, useUpdateEffect} from '@react-aria/utils';
2020
import {ComboBoxState} from '@react-stately/combobox';
2121
import {dispatchVirtualFocus} from '@react-aria/focus';
2222
import {FocusEvent, InputHTMLAttributes, KeyboardEvent, TouchEvent, useEffect, useMemo, useRef} from 'react';
@@ -220,6 +220,8 @@ export function useComboBox<T>(props: AriaComboBoxOptions<T>, state: ComboBoxSta
220220
[privateValidationStateProp]: state
221221
}, inputRef);
222222

223+
useFormReset(inputRef, state.defaultSelectedKey, state.setSelectedKey);
224+
223225
// Press handlers for the ComboBox button
224226
let onPress = (e: PressEvent) => {
225227
if (e.pointerType === 'touch') {

packages/@react-spectrum/combobox/test/ComboBox.test.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5268,26 +5268,30 @@ describe('ComboBox', function () {
52685268

52695269
if (parseInt(React.version, 10) >= 19) {
52705270
it('resets to defaultSelectedKey when submitting form action', async () => {
5271-
function Test() {
5271+
function Test(props) {
52725272
const [value, formAction] = React.useActionState(() => '2', '1');
52735273

52745274
return (
52755275
<Provider theme={theme}>
52765276
<form action={formAction}>
5277-
<ExampleComboBox defaultSelectedKey={value} />
5277+
<ExampleComboBox defaultSelectedKey={value} name="combobox" {...props} />
52785278
<input type="submit" data-testid="submit" />
52795279
</form>
52805280
</Provider>
52815281
);
52825282
}
52835283

5284-
let {getByTestId, getByRole} = render(<Test />);
5284+
let {getByTestId, getByRole, rerender} = render(<Test />);
52855285
let input = getByRole('combobox');
52865286
expect(input).toHaveValue('One');
52875287

52885288
let button = getByTestId('submit');
52895289
await act(async () => await user.click(button));
52905290
expect(input).toHaveValue('Two');
5291+
5292+
rerender(<Test formValue="key" />);
5293+
await act(async () => await user.click(button));
5294+
expect(document.querySelector('input[name=combobox]')).toHaveValue('2');
52915295
});
52925296
}
52935297

@@ -5597,26 +5601,30 @@ describe('ComboBox', function () {
55975601

55985602
if (parseInt(React.version, 10) >= 19) {
55995603
it('resets to defaultSelectedKey when submitting form action', async () => {
5600-
function Test() {
5604+
function Test(props) {
56015605
const [value, formAction] = React.useActionState(() => '2', '1');
56025606

56035607
return (
56045608
<Provider theme={theme}>
56055609
<form action={formAction}>
5606-
<ExampleComboBox name="combobox" defaultSelectedKey={value} />
5610+
<ExampleComboBox name="combobox" defaultSelectedKey={value} {...props} />
56075611
<input type="submit" data-testid="submit" />
56085612
</form>
56095613
</Provider>
56105614
);
56115615
}
56125616

5613-
let {getByTestId} = render(<Test />);
5617+
let {getByTestId, rerender} = render(<Test />);
56145618
let input = document.querySelector('input[name=combobox]');
56155619
expect(input).toHaveValue('One');
56165620

56175621
let button = getByTestId('submit');
56185622
await act(async () => await user.click(button));
56195623
expect(input).toHaveValue('Two');
5624+
5625+
rerender(<Test formValue="key" />);
5626+
await act(async () => await user.click(button));
5627+
expect(input).toHaveValue('2');
56205628
});
56215629
}
56225630

packages/react-aria-components/test/ComboBox.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,41 @@ describe('ComboBox', () => {
256256
expect(document.querySelector('input[type=hidden]')).toBeNull();
257257
});
258258

259+
it('should support form reset', async () => {
260+
const tree = render(
261+
<form>
262+
<ComboBox defaultSelectedKey="2" name="combobox">
263+
<Label>Favorite Animal</Label>
264+
<Input />
265+
<Button />
266+
<FieldError />
267+
<Popover>
268+
<ListBox>
269+
<ListBoxItem id="1">Cat</ListBoxItem>
270+
<ListBoxItem id="2">Dog</ListBoxItem>
271+
<ListBoxItem id="3">Kangaroo</ListBoxItem>
272+
</ListBox>
273+
</Popover>
274+
</ComboBox>
275+
<input type="reset" />
276+
</form>
277+
);
278+
279+
const comboboxTester = testUtilUser.createTester('ComboBox', {root: tree.container});
280+
const combobox = comboboxTester.combobox;
281+
282+
expect(combobox).toHaveValue('Dog');
283+
await comboboxTester.open();
284+
285+
const options = comboboxTester.options();
286+
await user.click(options[0]);
287+
expect(combobox).toHaveValue('Cat');
288+
289+
await user.click(document.querySelector('input[type="reset"]'));
290+
expect(combobox).toHaveValue('Dog');
291+
expect(document.querySelector('input[name=combobox]')).toHaveValue('2');
292+
});
293+
259294
it('should render data- attributes on outer element', () => {
260295
let {getAllByTestId} = render(
261296
<TestComboBox data-testid="combo-box" />

0 commit comments

Comments
 (0)