diff --git a/radio/internal/single-selection-controller.ts b/radio/internal/single-selection-controller.ts index e1bdc667d0..c84922be92 100644 --- a/radio/internal/single-selection-controller.ts +++ b/radio/internal/single-selection-controller.ts @@ -236,8 +236,11 @@ export class SingleSelectionController implements ReactiveController { nextSibling.checked = true; nextSibling.tabIndex = 0; nextSibling.focus(); - // Fire a change event since the change is triggered by a user action. - // This matches native behavior. + // Fire an input event first, then a change event since both are triggered + // by a user action. This matches native behavior. + nextSibling.dispatchEvent( + new InputEvent('input', {bubbles: true, composed: true}), + ); nextSibling.dispatchEvent(new Event('change', {bubbles: true})); break; diff --git a/radio/radio_test.ts b/radio/radio_test.ts index eed1b08bff..eb56c6d61a 100644 --- a/radio/radio_test.ts +++ b/radio/radio_test.ts @@ -183,6 +183,21 @@ describe('', () => { expect(changeHandler).toHaveBeenCalledTimes(1); }); + it('dispatched an input event on user navigation', async () => { + const {harnesses, root} = await setupTest(radioGroupPreSelected); + const inputHandler = jasmine.createSpy('inputHandler'); + root.addEventListener('input', inputHandler); + const [, a2] = harnesses; + expect(a2.element.checked) + .withContext('default checked radio') + .toBeTrue(); + + await simulateKeyDown(a2.element, 'ArrowRight'); + + expect(inputHandler).toHaveBeenCalledTimes(1); + expect(inputHandler).toHaveBeenCalledWith(jasmine.any(InputEvent)); + }); + it('Using arrow right on the last radio should select the first radio in that group', async () => { const {harnesses} = await setupTest(radioGroupPreSelected); const [a1, a2, a3, b1] = harnesses;