Skip to content

Conversation

@mrsants
Copy link

@mrsants mrsants commented Dec 19, 2025

Closes

✅ 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:

yarn test packages/@react-aria/utils

🧢 Your Project:

@mrsants mrsants closed this Dec 19, 2025
@mrsants mrsants reopened this Dec 19, 2025
@snowystinger
Copy link
Member

Thanks for the PR, can you explain where this need is coming from? What environment are you running in?

@mrsants
Copy link
Author

mrsants commented Jan 7, 2026

Thanks for the PR, can you explain where this need is coming from? What environment are you running in?

This change addresses a runtime error when Spectrum / React Aria is used in React Native environments (e.g. React Native Web / Expo).

In these environments, window and document may exist, but document.body is undefined. runAfterTransition currently assumes a full DOM and attempts to attach listeners to document.body, which causes crashes (addEventListener of undefined).

The hasDOM guard ensures DOM access only happens when a real browser DOM is available, preserving existing web behavior while preventing errors in non-DOM runtimes.

@snowystinger
Copy link
Member

Thanks for the extra information. I don't quite follow why you're trying to use React Aria if there is no DOM though?

@mrsants
Copy link
Author

mrsants commented Jan 8, 2026

We already use React Aria today in this setup, and this DOM-related issue is something we’re already tracking.

Even though the target runtime is React Native, parts of the app run in hybrid environments (e.g. React Native Web / Expo), where React Aria is still consumed but a full DOM is not guaranteed. This specific failure has an existing issue associated with it, and this change is meant to safely handle that scenario rather than introduce new usage.

@snowystinger
Copy link
Member

snowystinger commented Jan 8, 2026

We definitely assume a full DOM. I can't imagine this is the only issue, more that it's only the tip of the iceberg.

My question was more, why load react-aria in the native case, why not have a different implementation? We envisioned stately as being shareable with React Native, but not react-aria.

This specific failure has an existing issue associated with it

Where is this issue?

@mrsants
Copy link
Author

mrsants commented Jan 8, 2026

In our case, React Aria is already part of the dependency graph due to shared code paths between web and hybrid targets (e.g. React Native Web / Expo). While we are not intentionally relying on React Aria behavior in a pure native runtime, some modules are still imported and evaluated during initialization.

This change is not meant to make React Aria supported in React Native, but rather to prevent a hard crash during module evaluation in hybrid environments where React Aria ends up being loaded indirectly. The guard is a defensive measure to avoid accessing the DOM when it is not fully available.

I agree that the longer-term and cleaner solution is a stricter separation between web and native implementations. This change is intended to improve resilience in the current setup without altering expected web behavior.

@snowystinger
Copy link
Member

It sounds like this PR is adding code to guard against something which shouldn't be happening? So we're increasing the size of our packages for everyone. Can you instead use a patch (ie patch-package or yarn patch) until you're able to more cleanly separate them?

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.

2 participants