Skip to content

Radio button/checkbox click events don't trigger React onChange handlers in v20.0.0 (regression) #1940

@tomoakikusaba

Description

@tomoakikusaba

Bug Description

Radio button and checkbox click events do not trigger React onChange handlers in happy-dom v20.0.0, despite being fixed in earlier versions. This is a regression from v9.10.3 and v14.10.2.

Versions

  • happy-dom: 20.0.0
  • Affected: Radio buttons and checkboxes with React Hook Form
  • Environment: vitest v2.1.9, React 18, @testing-library/user-event

Previous Fixes

Reproduction

Test Code

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

it('radio button onChange should trigger', async () => {
  const handleChange = vi.fn();
  const user = userEvent.setup();
  
  render(
    <div>
      <label>
        <input type="radio" name="test" value="option1" onChange={handleChange} />
        Option 1
      </label>
      <label>
        <input type="radio" name="test" value="option2" onChange={handleChange} />
        Option 2
      </label>
    </div>
  );

  const radio2 = screen.getByRole('radio', { name: /Option 2/i });
  await user.click(radio2);
  
  // ❌ FAILS: onChange is not triggered
  await waitFor(() => {
    expect(handleChange).toHaveBeenCalled();
  });
});
vitest.config.ts
export default defineConfig({
  test: {
    environment: 'happy-dom',
    environmentOptions: {
      happyDOM: {
        settings: {
          disableJavaScriptEvaluation: false, // Tried this, doesn't help
        },
      },
    },
  },
});

Expected Behavior

Clicking a radio button or checkbox should:

  1. Update the checked property
  2. Trigger the change event
  3. Call React's onChange handler

This worked correctly in v9.10.3 - v19.x.

Actual Behavior

  • checked property does not update
  • change event is not fired
  • ❌ React onChange handler is not called

Attempted Workarounds (all failed)

  1. Setting disableJavaScriptEvaluation: false in vitest config
  2. Using fireEvent.click() instead of user.click()
  3. Clicking the label element instead of the input
  4. Manually dispatching change events
  5. Using act() wrapper

Environment

  • Node.js: v20.x
  • OS: Linux
  • Testing Framework: Vitest 2.1.9
  • React: 18.x
  • React Testing Library: 16.x
  • React Hook Form: 7.x

Additional Context

We cannot downgrade to v19 or earlier due to CVE-2025-61927 (CVSS 9.4 - Critical), which requires v20.0.0+.

Related Issues

Would appreciate any guidance on this regression. Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions