Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/@react-aria/listbox/src/useListBoxSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ export function useListBoxSection(props: AriaListBoxSectionProps): ListBoxSectio
role: 'presentation'
},
headingProps: heading ? {
// Techincally, listbox cannot contain headings according to ARIA.
// Technically, listbox cannot contain headings according to ARIA.
// We hide the heading from assistive technology, using role="presentation",
// and only use it as a visual label for the nested group.
id: headingId,
role: 'presentation'
role: 'presentation',
onMouseDown: (e) => {
// Prevent DOM focus from moving on mouse down when using virtual focus
e.preventDefault();
}
} : {},
groupProps: {
role: 'group',
Expand Down
66 changes: 66 additions & 0 deletions packages/react-aria-components/test/ComboBox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,4 +482,70 @@ describe('ComboBox', () => {
expect(onAction).toHaveBeenCalledTimes(2);
expect(comboboxTester.combobox).toHaveValue('Cat');
});

it('should not close the combobox when clicking on a section header', async () => {
let tree = render(
<ComboBox>
<Label>Preferred fruit or vegetable</Label>
<Input />
<Button />
<Popover>
<ListBox>
<ListBoxSection>
<Header>Fruit</Header>
<ListBoxItem id="Apple">Apple</ListBoxItem>
<ListBoxItem id="Banana">Banana</ListBoxItem>
</ListBoxSection>
<ListBoxSection>
<Header>Vegetable</Header>
<ListBoxItem id="Cabbage">Cabbage</ListBoxItem>
<ListBoxItem id="Broccoli">Broccoli</ListBoxItem>
</ListBoxSection>
</ListBox>
</Popover>
</ComboBox>
);

let comboboxTester = testUtilUser.createTester('ComboBox', {root: tree.container});
let button = tree.getByRole('button');

// Open the combobox
await user.click(button);
act(() => {
jest.runAllTimers();
});

// Verify the listbox is open
let listbox = tree.getByRole('listbox');
expect(listbox).toBeInTheDocument();
expect(listbox).toBeVisible();

// Find and click on a section header
let fruitHeader = tree.getByText('Fruit');
expect(fruitHeader).toBeInTheDocument();

await user.click(fruitHeader);
act(() => {
jest.runAllTimers();
});

// Verify the listbox is still open
listbox = tree.getByRole('listbox');
expect(listbox).toBeInTheDocument();
expect(listbox).toBeVisible();

// Verify we can still interact with options
let options = comboboxTester.options();
expect(options.length).toBeGreaterThan(0);

// Click an option
await user.click(options[0]);
act(() => {
jest.runAllTimers();
});

// Verify the combobox is closed and the value is updated
expect(tree.queryByRole('listbox')).toBeNull();
expect(comboboxTester.combobox).toHaveValue('Apple');
});
});