fix(connect): stop components hanging on double quotes in init params by BhodiSea · Pull Request #2680 · stripe/stripe-react-native · GitHub
Skip to content

fix(connect): stop components hanging on double quotes in init params - #2680

Closed
BhodiSea wants to merge 2 commits into
stripe:masterfrom
BhodiSea:fix/connect-injected-object-escaping
Closed

BhodiSea wants to merge 2 commits into
stripe:masterfrom
BhodiSea:fix/connect-injected-object-escaping

Conversation

@BhodiSea

Copy link
Copy Markdown
Contributor

Summary

EmbeddedComponent now passes the init params in injectedJavaScriptBeforeContentLoaded, this replaces the empty '(function() {})();' placeholder.

The script (src/connect/injectedObjectScript.ts) defines window.ReactNativeWebView.injectedObjectJson(), which the Connect page already reads on startup.

It returns the same JSON from a JS string literal and is read-only, so react-native-webview's own definition from injectedJavaScriptObject can't replace it, whichever runs first.

  • injectedJavaScriptObject is still passed, unchanged.

  • On Android, react-native-webview 13.6.0–13.13.0 serves injectedObjectJson() from a Java method (RNCWebView.java#L286-L291, #L425-L426 @ v13.13.0) that page scripts can't override and that never had this bug. Expo SDK 50–52 pin versions in that range.

  • Everywhere else the prop is only a fallback: if the script fails, the component behaves as on master.

  • The script is non-empty, so Android keeps re-injecting the object on each page start, which is what the placeholder was for (react-native-webview#3326).

  • No Connect page or public API change.

Motivation

If any init param (appearance, locale, fonts, or a component prop) contains ", \, a newline, or a backtick, the component stays on its loader and never calls onLoadError. An ordinary CSS font stack is enough.

react-native-webview embeds the injectedJavaScriptObject JSON in a JS template literal, return `%@`;:

The template literal turns \" into " and \\ into \, so the page's startup JSON.parse throws. The Android WebView console shows:

Uncaught SyntaxError: Expected ',' or '}' after property value in JSON at position 966

This is reported upstream as react-native-webview#3957 (iOS) and #3942 (Android).

The proposed fixes (#3958 and #3929) are still open.

Stripe SDK's default font avoids the bug only because it single-quotes family names (EmbeddedComponent.tsx#L902-L903).

Why fix it here: the react-native-webview peer dependency is * (package.json#L106), so an upstream fix only reaches apps that upgrade; this change works with the versions apps already have.

Repro: in example-stripe-connect, set the Retro preset's fontFamily (appearancePresets.ts#L171) to '"Courier New", Courier, monospace', choose Retro, and open Account onboarding.

Testing

  • I tested this manually
  • I added automated tests

Manual: example-stripe-connect (React Native 0.81.5) with react-native-webview 13.15.0 and 13.13.0, on an iOS 26.5 simulator and an Android 16 emulator (WebView 133): Retro preset → Account onboarding → Show Onboarding, then a screenshot after ~30 s.

Run Code fontFamily iOS, 13.15.0 Android, 13.15.0 Android, 13.13.0
A master "Courier New", Courier, monospace loader never ends, no onLoadError loader never ends, SyntaxError above loads
B master Courier (control) loads loads –
C this PR "Courier New", Courier, monospace loads, Courier New applied loads loads
D this PR "O'Reilly Sans", "Courier New", monospace loads loads loads
  • 13.13.0 is the last Android version with the Java method. Master already works there, so that column is a regression check. Without injectedJavaScriptObject, the page there loads with the app's appearance missing, which is why the prop stays.

  • Live appearance changes (iOS, Payouts). A new script makes react-native-webview re-install its user scripts, so I switched presets twice while the component was mounted: each change applied without a page reload, and "Sign in to edit payout destinations" still reached the app (openAuthenticatedWebView).

Automated:

  • injectedObjectScript.test.ts runs the script in a Node vm context.
    • Quoted, backslash, newline, backtick, ${…}, U+2028/U+2029, and non-ASCII values round-trip exactly.
    • The value survives react-native-webview's iOS and Android definitions running after it, replaces one made before it with a read-only one, and survives a second run of the script.
    • Control: react-native-webview's iOS definition alone corrupts a double-quoted value.
  • EmbeddedComponent.test.tsx: the script carries the same init params as injectedJavaScriptObject, including the default font. Both new tests fail on master.
  • yarn typescript, yarn lint, yarn test, yarn test:package-types, cd example && yarn typescript, and yarn api-extractor:check pass on Node 22.

Documentation

Select one:

  • I have added relevant documentation for my changes.
  • This PR does not result in any developer-facing changes.

Added a CHANGELOG entry under Unreleased → Fixes.

AI assistance: I used Claude Code to trace the react-native-webview code paths, draft the change and tests, and drive the simulator and emulator runs. I reviewed the diff and the recordings.

react-native-webview's injectedJavaScriptObject embeds the JSON in a JS
template literal (iOS; Android from 13.13.1), so a double quote,
backslash, newline, or backtick in any init param stops the Connect page
from starting: the component never leaves its loader and never calls
onLoadError. A double-quoted family name in
appearance.variables.fontFamily is enough.

Also pass the init params as an injectedJavaScriptBeforeContentLoaded
script, replacing the empty placeholder. It defines
window.ReactNativeWebView.injectedObjectJson() read-only, with the JSON
in a string literal, so react-native-webview's definition can't replace
it. Keep injectedJavaScriptObject: on Android, react-native-webview
13.6.0-13.13.0 serves it from a Java method that page scripts can't
override and that never had this bug.
@BhodiSea
BhodiSea requested review from a team as code owners September 23, 2026 11:02
@cla-assistant

cla-assistant Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@cla-assistant

cla-assistant Bot commented Sep 23, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@BhodiSea

BhodiSea commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

@BhodiSea BhodiSea closed this by deleting the head repository Oct 4, 2026
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.

1 participant