Skip to content

fix: activate <summary> per [Enter] and [Space] - #1335

Open
ybai08 wants to merge 1 commit into
testing-library:mainfrom
ybai08:fix/summary-keyboard-activation
Open

ybai08 wants to merge 1 commit into
testing-library:mainfrom
ybai08:fix/summary-keyboard-activation

Conversation

@ybai08

@ybai08 ybai08 commented Oct 17, 2026

Copy link
Copy Markdown

What

user.keyboard('{Enter}') and user.keyboard(' ') on a focused <summary> now dispatch a click on it, the way they do for a <button>. That toggles the parent <details>.

Closes #1264

Why

<details> > <summary> is already focusable in user-event (FOCUSABLE_SELECTOR includes details > summary), but pressing Enter or Space on it does nothing, so a disclosure widget can't be tested by keyboard.

Event sequence in headless Chromium 153 (Playwright keyboard.press) on a focused <summary>:

  • Enter: keydown, keypress, click (detail 0), keyup, then toggle
  • Space: keydown, keypress, keyup, click (detail 0), then toggle. With keydown only, nothing toggles; the click comes on keyup.
  • preventDefault() on keydown suppresses the click for Enter.
  • An orphan <summary tabindex="0"> (not inside a <details>) gets no click for either key.

That matches the existing button handling: click after keypress for Enter, click after keyup for Space.

How

  • New helper isSummaryForParentDetails() in src/utils/click/. It matches only the first <summary> child of a <details>, which is the one with activation behavior per the HTML spec ("the summary for its parent details").
  • keypress behavior: Enter on such a summary dispatches click.
  • keyup behavior: Space on such a summary dispatches click.

Checklist

  • Documentation N/A
  • Tests
  • Ready to be merged

New tests:

  • tests/event/behavior/keypress.ts and keyup.ts: click on the summary of a details element, but not on a summary outside a details element or on a second summary
  • tests/keyboard/index.ts: [Enter] opens and [Space] closes the <details>

The "on summary of details" cases and the keyboard test fail on main and pass with this change.

What was run:

  • npx jest: 55 suites, 527 tests pass
  • npm run validate (typecheck): passes
  • eslint on the changed files: no new warnings
  • prettier --check on the new and test files: passes
  • npm run test:toolbox (Node DTL10, Node DTL8, Chrome DTL10): all new tests pass in all three environments. The Chrome conductor's hard-coded /usr/bin/chromium was pointed at a local Chrome for Testing build (not committed). The remaining toolbox failures on this macOS machine are the same as on main.

Not run: the CI Linux environment, Firefox/WebKit.

Browsers treat the summary of a `<details>` element like a button:
`Enter` dispatches a `click` after `keypress` and `Space` dispatches a
`click` after `keyup`. The `click` toggles the `<details>` element.

Only the first `<summary>` child of a `<details>` element is activated.

Closes testing-library#1264
@snowystinger

Copy link
Copy Markdown
Contributor

Thanks for the PR. Can you explain why your solution looks different than the suggested solution here #1264 (comment) ? where there places that isClickableInput is called that this shouldn't be included?

@ybai08

ybai08 commented Oct 19, 2026

Copy link
Copy Markdown
Author

Good question. I didn't put it in isClickableInput for these reasons:

  1. isClickableInput has a second caller. hasNoSelection() (src/utils/focus/selection.ts) uses it, and setSelectionPerMouseDown() returns early for those elements. Adding <summary> there would also change how pointer selection is tracked inside a <summary>, which is a separate behaviour from keyboard activation. It would also make the element is ClickableInputOrButton type guard claim that a <summary> is an HTMLButtonElement | HTMLInputElement.
  2. isClickableInput only covers [Space]. It's only consulted in the keyup behavior. A <summary> is activated by [Enter] too, and like <button> that happens on keypress, so keypress.ts needs the same check either way.
  3. The element to check is the <summary>, not the <details>. The <summary> is the focusable element that receives the key events, and per the HTML spec only the first <summary> child of a <details> is its summary (others don't toggle anything). That's why the helper checks parent and position instead of just the tag name. There are tests for a <summary> outside <details> and for a second <summary>.

If you'd rather keep a single list, I can add a separate isKeyboardActivatable()-style helper that both keyup and keypress use, and leave isClickableInput/hasNoSelection alone.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User keyboard events don't trigger the <details /> element

2 participants