Skip to content

Omit undefined optional props on AcceleratedCheckoutButtons - #521

Open
JoaoPauloCMarra wants to merge 2 commits into
Shopify:mainfrom
JoaoPauloCMarra:fix/accelerated-checkout-buttons-undefined-props
Open

JoaoPauloCMarra wants to merge 2 commits into
Shopify:mainfrom
JoaoPauloCMarra:fix/accelerated-checkout-buttons-undefined-props

Conversation

@JoaoPauloCMarra

Copy link
Copy Markdown

Summary

  • Pass applePayLabel, applePayStyle, cornerRadius, and wallets to RCTAcceleratedCheckoutButtons only when they are defined, instead of always passing them (and therefore undefined) to the native component.
  • Omit height from the style until native reports a size via onSizeChange, instead of forcing height: undefined into the style on first render.

Reproduction (3.9.0)

Render AcceleratedCheckoutButtons without the optional props, e.g.:

<AcceleratedCheckoutButtons
  cartId={cartId}
  onComplete={onComplete}
  onFail={onFail}
/>

The wrapper renders the native component with applePayLabel={undefined}, applePayStyle={undefined}, cornerRadius={undefined}, wallets={undefined}, and style={{flex: 1, height: undefined}}. The undefined values are serialized across the JS→native bridge instead of the props simply being absent.

Root cause

On the native side (iOS, ios/AcceleratedCheckoutButtons.swift), the optional props are @objc var cornerRadius: NSNumber?, wallets: [String]?, applePayLabel: String?, applePayStyle: String? and the comment above them says the values are intentionally nil so that the kit defaults are used. The component relies on distinguishing "prop absent" from "prop present":

  • wallets explicitly provided and empty means render nothing (wallets != nil && shopifyWallets.isEmpty); when the prop is absent, the SDK decides the default wallets. An undefined/null value crossing the bridge does not reliably map to "absent", so the default-wallet fallback can be clobbered.
  • applePayStyle is always funneled through PayWithApplePayButtonStyle.from(applePayStyle) in updateView(), so a value that arrives as an unexpected representation of undefined can steer the Apple Pay button away from its automatic default styling.
  • Every didSet on these props triggers updateView() (and for wallets, an intrinsic-content-size invalidation), so explicitly serialized undefined values cause redundant native re-renders at mount.
  • style: {...defaultStyles, height: undefined} forces an explicit undefined height into the Yoga style on first render instead of leaving the height unset until onSizeChange reports one.

Why the fix works

Spreading each optional prop only when it is defined ({...(prop === undefined ? {} : {prop}})) keeps the prop absent from the element, which is the representation native already handles correctly as "use the kit default". The same idea applies to height: when dynamicHeight is undefined, we pass defaultStyles without a height key rather than height: undefined.

Testing

  • Added two tests to tests/AcceleratedCheckoutButtons.test.tsx:
    • omits applePayLabel, applePayStyle, cornerRadius, and wallets from the native element when not provided
    • omits height from the style until onSizeChange fires (existing test already covers that the reported height is then applied)
  • pnpm test — 125 tests, 6 suites, all passing
  • pnpm lint in modules/@shopify/checkout-sheet-kit (typecheck + eslint) — passing

Relationship to #515 / #502

This PR intentionally does not touch flex: 1 / hit-area behavior — that is covered by #515 (fixes #502). The changes here are complementary: #515 makes the reported native height participate in layout, while this PR stops undefined props (including an explicit undefined height) from being serialized across the bridge at mount. If both land, the style line will need a trivial merge.

Pass applePayLabel, applePayStyle, cornerRadius, and wallets to the
native component only when they are defined, and omit height from the
style until native reports a size, so undefined values are not
serialized across the bridge where they can clobber kit defaults.
@JoaoPauloCMarra
JoaoPauloCMarra requested a review from a team as a code owner September 1, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant