Skip to content

feat: warn when firing events on disabled elements - #1934

Open
trinadhkoya wants to merge 1 commit into
callstack:mainfrom
trinadhkoya:feat/disabled-event-warning
Open

feat: warn when firing events on disabled elements#1934
trinadhkoya wants to merge 1 commit into
callstack:mainfrom
trinadhkoya:feat/disabled-event-warning

Conversation

@trinadhkoya

Copy link
Copy Markdown

Summary

Closes #1718.

Firing an event on a disabled element (e.g. a Pressable with disabled={true}) currently triggers no handler silently, which is confusing when debugging why a test "does nothing". This adds a warning in that case, opt-out via configure({ disabledEventWarning: false }).

▲ Tried to fire the "press" event on a disabled element, so no handler was called.
  If this is intentional, you can disable this warning via `configure({ disabledEventWarning: false })`.

Implementation

  • Detection reuses the existing computeAriaDisabled helper (the one behind toBeDisabled) and emits through the existing logger.
  • The warning is gated on no handler being found, so:
    • events that bubble to an enabled parent do not warn (a handler did run);
    • pointerEvents="none" does not warn (it isn't a disabled state).
  • TextInput editability (editable={false}) is intentionally excluded — it's a distinct concept from disabled state, and warning on changeText/focus there produced false positives.
  • New config option disabledEventWarning: boolean, on by default.

Scope

This PR covers fireEvent. userEvent uses a separate dispatch path (user-event/press) with its own disabled handling, so I've left it out here — happy to follow up with a matching change for userEvent if you're good with this approach.

Open question

Per the discussion on #1718: I've defaulted the warning to on (opt-out), matching the leaning in the thread. Happy to switch it to opt-in for the first release if you'd prefer.

Testing

  • Added tests in fire-event.test.tsx: warns on disabled element, does not warn when bubbling to an enabled parent, does not warn for pointerEvents="none", and is silenced by configure({ disabledEventWarning: false }).
  • Updated the configure() default-config assertion and documented the option in config.mdx.
  • yarn typecheck, yarn lint, yarn format:check, and the full yarn test suite (817 tests) all pass.

Copilot AI lite review requested due to automatic review settings September 5, 2026 18:03
@trinadhkoya
trinadhkoya force-pushed the feat/disabled-event-warning branch from 931ca0e to 0949859 Compare September 5, 2026 18:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

A test-local logger.warn spy is restored in a way that can leak mocks if the test fails before cleanup.

Pull request overview

Adds a configurable warning to help diagnose fireEvent calls that silently do nothing when the target element is disabled, leveraging existing disabled-state computation and the shared logger.

Changes:

  • Emit a logger.warn when fireEvent finds no handler and the nearest touch responder is disabled (opt-out via configure({ disabledEventWarning: false })).
  • Add disabledEventWarning to global config (default true) and update documentation.
  • Extend fire-event and config tests to cover the warning behavior and default config assertions.
File summaries
File Description
website/docs/14.x/docs/api/misc/config.mdx Documents the new disabledEventWarning configuration option and opt-out usage.
src/fire-event.ts Adds disabled-target detection and a warning when fireEvent results in no handler due to disabled state.
src/config.ts Introduces disabledEventWarning in Config, default config, and configure() plumbing.
src/tests/fire-event.test.tsx Adds tests validating warning behavior and config opt-out; suppresses warning output in relevant suites.
src/tests/config.test.ts Updates default-config equality assertion to include disabledEventWarning: true.
Review details

Suppressed comments (1)

src/tests/fire-event.test.tsx:907

  • logger.warn is spied and restored manually at the end of the test. If an assertion throws before the restore line, the spy will leak into later tests and can hide/alter warning expectations.

Wrap the test body in a try/finally (or move the spy to a beforeEach/afterEach) so the restore always runs.

    const warnSpy = jest.spyOn(logger, 'warn').mockImplementation(() => {});
    function TestChildTouchableComponent({
      onPress,
      someProp,
    }: {
  • Files reviewed: 5/5 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Firing an event on a disabled element (e.g. a `Pressable` with
`disabled={true}`) silently triggers no handler, which is confusing when
debugging tests. Emit a warning in that case, reusing `computeAriaDisabled`
for detection and the existing `logger`.

- Gated on no handler being found, so events that bubble to an enabled
  parent do not warn.
- Scoped to disabled state only; `pointerEvents="none"` and `TextInput`
  editability are intentionally excluded to avoid false positives.
- Opt-out via `configure({ disabledEventWarning: false })`; on by default.

Closes callstack#1718 (fireEvent scope; userEvent is a follow-up).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new TextInput exclusion in the warning logic is broader than the PR description’s intent and may incorrectly suppress warnings for truly disabled TextInput elements.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/fire-event.ts
Comment on lines +148 to +152
// `TextInput` editability (`editable={false}`) is a separate concern from
// disabled state, so we don't warn about it here to avoid false positives.
if (isHostTextInput(target)) {
return;
}
@trinadhkoya

Copy link
Copy Markdown
Author

Heads-up from my side: after opening this I realized #1726 already resolves #1717/#1718 with a fuller design — a unified configure({ debug: true }) debugging mode covering both fireEvent and userEvent. That's clearly the better direction than the dedicated, on-by-default disabledEventWarning flag I proposed here, and I don't want to add a competing API.

I'd rather help land your approach. Happy to do whichever is most useful:

Just let me know what you'd prefer. If you'd welcome the help on #1726, I'm glad to put the work in.

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.

UX: feedback when event could not be triggered due to disabled state, etc

2 participants