Skip to content

Conversation

@hasegawa-101
Copy link

Closes #8732

Added onKeyDown prop to ListBoxItem to support custom keyboard event handling for individual items,
enabling features like deleting items with Delete/Backspace keys.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub
    Issue
    .
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria
    Practices

📝 Test Instructions:

  1. Run Storybook: yarn start
  2. Navigate to "ListBox With Keyboard Delete" story
  3. Focus on an item and press Delete or Backspace
  4. Verify the item is removed and keyboard navigation still works

🧢 Your Project:

Open source contribution

@hasegawa-101 hasegawa-101 changed the title Add onKeyDown prop to ListBoxItem for custom keyboard handling feat: add onKeyDown prop to ListBoxItem for custom keyboard handling Nov 13, 2025
@hasegawa-101 hasegawa-101 marked this pull request as ready for review November 13, 2025 17:36
Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for starting this, would you mind removing the docs and storybook in favour of a unit test? it can be added just after this describe block

describe('press events', () => {

@hasegawa-101
Copy link
Author

@snowystinger

Thanks for the review! I've addressed your feedback. Please take another look.

@nwidynski
Copy link
Contributor

nwidynski commented Nov 14, 2025

This should be using useKeyboard instead of native event listeners, otherwise we leak the event upwards.

let {getAllByRole} = renderListbox({}, {onKeyDown});
let options = getAllByRole('option');

fireEvent.keyDown(options[0], {key: 'Delete'});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fireEvent.keyDown(options[0], {key: 'Delete'});
await user.tab();
await user.keyboard('ArrowDown');

@hasegawa-101
Copy link
Author

Fixed! I've updated the test to use userEvent.keyboard() instead of fireEvent.keyDown() to prevent event leaking 🙏

# Conflicts:
#	packages/react-aria-components/src/ListBox.tsx

describe('onKeyDown', () => {
it('should call key handler when key is pressed on item', async () => {
let onKeyDown = jest.fn((e) => e.continuePropagation());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question to team, do we want to use useKeyboard for this, it stops events by default so we MUST call continuePropagation here for the "Escape" key to clear the selection.

This is not ideal because it causes the event to continue by default instead through all other event handlers. See my thoughts on this in the description of #8775

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not ideal because it causes the event to continue by default instead through all other event handlers.

Hm, maybe I’m remembering something wrong but isn't that only an issue because the handlers further up do not consistently useKeyboard themselves?

If that were the case propagation wouldnt flow upwards uncontrollably, since it would be stopped at every level if not explicitly continued.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ListBox: Backspace/Delete

3 participants