Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,178 @@ shopify.addEventListener('geolocationRequest', async (event: GeolocationRequestE

---

## Accelerated Checkouts

Accelerated checkout buttons surface Apple Pay and Shop Pay options earlier in the buyer journey so more orders complete without leaving your app.

### Prerequisites

- iOS 16 or later
- The `write_cart_wallet_payments` access scope ([request access](https://www.appsheet.com/start/1ff317b6-2da1-4f39-b041-c01cfada6098))
- Apple Pay payment processing certificates ([setup guide](https://shopify.dev/docs/storefronts/mobile/create-apple-payment-processing-certificates))
- A device configured for Apple Pay ([Apple setup instructions](https://developer.apple.com/documentation/passkit/setting-up-apple-pay))

### Configure the integration

Pass an `acceleratedCheckouts` configuration when setting up the provider or `ShopifyCheckoutSheet` instance. This connects the accelerated checkout buttons to your storefront.

```tsx
import {ShopifyCheckoutSheetProvider} from '@shopify/checkout-sheet-kit';

const config = {
acceleratedCheckouts: {
storefrontDomain: 'your-shop.myshopify.com',
storefrontAccessToken: 'your-storefront-access-token',
customer: {
// For authenticated customers
accessToken: 'customer-access-token',
// OR for guest customers
// email: 'customer@example.com',
// phoneNumber: '0123456789',
},
wallets: {
applePay: {
merchantIdentifier: 'merchant.com.yourcompany',
contactFields: ['email', 'phone'],
// Optionally restrict shipping countries (ISO 3166-1 alpha-2)
// supportedShippingCountries: ['US', 'CA'],
},
},
},
};

function App() {
return (
<ShopifyCheckoutSheetProvider configuration={config}>
<YourApp />
</ShopifyCheckoutSheetProvider>
);
}
```

> [!WARNING]
> Do not provide both `accessToken` and `email`/`phoneNumber` together. For authenticated customers, email and phone are fetched automatically from the Shopify account.

### Render accelerated checkout buttons

Use `AcceleratedCheckoutButtons` to attach accelerated checkout calls-to-action to product or cart surfaces once you have a valid cart ID or product variant ID from the Storefront API.

```tsx
import {
AcceleratedCheckoutButtons,
AcceleratedCheckoutWallet,
} from '@shopify/checkout-sheet-kit';

function CartFooter({cartId}: {cartId: string}) {
return (
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay, AcceleratedCheckoutWallet.applePay]}
/>
);
}
```

You can also render buttons for a single product variant:

```tsx
<AcceleratedCheckoutButtons
variantId={variantId}
quantity={1}
wallets={[AcceleratedCheckoutWallet.applePay]}
/>
```

#### Customize wallet options

Accelerated checkout buttons display every available wallet by default. Use `wallets` to show a subset or adjust the order.

```tsx
// Display only Shop Pay
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay]}
/>

// Display Shop Pay first, then Apple Pay
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay, AcceleratedCheckoutWallet.applePay]}
/>
```

#### Modify the Apple Pay button label

Use `applePayLabel` to map to the native `PayWithApplePayButtonLabel` values. The default is `plain`.

```tsx
import {ApplePayLabel} from '@shopify/checkout-sheet-kit';

<AcceleratedCheckoutButtons
cartId={cartId}
applePayLabel={ApplePayLabel.buy}
/>
```

#### Customize the Apple Pay button style

Use `applePayStyle` to set the color style of the Apple Pay button. The default is `automatic`, which adapts to the current appearance (light/dark mode).

```tsx
import {ApplePayStyle} from '@shopify/checkout-sheet-kit';

<AcceleratedCheckoutButtons
cartId={cartId}
applePayStyle={ApplePayStyle.whiteOutline}
/>
```

Available styles: `automatic`, `black`, `white`, `whiteOutline`.

#### Customize button corners

The `cornerRadius` prop lets you match the buttons to other calls-to-action in your app. Buttons default to an 8pt radius.

```tsx
// Pill-shaped buttons
<AcceleratedCheckoutButtons cartId={cartId} cornerRadius={16} />

// Square buttons
<AcceleratedCheckoutButtons cartId={cartId} cornerRadius={0} />
```

### Handle loading, errors, and lifecycle events

Attach lifecycle handlers to respond when buyers finish, cancel, or encounter an error.

```tsx
<AcceleratedCheckoutButtons
cartId={cartId}
onComplete={(event) => {
// Clear cart after successful checkout
clearCart();
}}
onFail={(error) => {
console.error('Accelerated checkout failed:', error);
}}
onCancel={() => {
analytics.track('accelerated_checkout_cancelled');
}}
onRenderStateChange={(event) => {
// event.state: 'loading' | 'rendered' | 'error'
setRenderState(event.state);
}}
onWebPixelEvent={(event) => {
analytics.track(event);
}}
onClickLink={(url) => {
Linking.openURL(url);
}}
/>
```

---

## Contributing

See the [contributing documentation](CONTRIBUTING.md) for details on how to get started.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Pod::Spec.new do |s|
s.source_files = "ios/*.{h,m,mm,swift}"

s.dependency "React-Core"
s.dependency "ShopifyCheckoutSheetKit", "~> 3.7.0"
s.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.7.0"
s.dependency "ShopifyCheckoutSheetKit", "~> 3.8.0"
s.dependency "ShopifyCheckoutSheetKit/AcceleratedCheckouts", "~> 3.8.0"

if fabric_enabled
# Use React Native's helper if available, otherwise add dependencies directly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,23 @@ extension PayWithApplePayButtonLabel {
"topUp": .topUp
]
}

// MARK: - Apple Pay Button Style

@available(iOS 16.0, *)
extension PayWithApplePayButtonStyle {
static func from(_ string: String?, fallback: PayWithApplePayButtonStyle = .automatic) -> PayWithApplePayButtonStyle {
guard let string, let value = map[string] else {
return fallback
}

return value
}

private static let map: [String: PayWithApplePayButtonStyle] = [
"automatic": .automatic,
"black": .black,
"white": .white,
"whiteOutline": .whiteOutline
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ class RCTAcceleratedCheckoutButtonsView: UIView {
}
}

@objc var applePayStyle: String? {
didSet {
updateView()
}
}

@objc var onFail: RCTBubblingEventBlock?
@objc var onComplete: RCTBubblingEventBlock?
@objc var onCancel: RCTBubblingEventBlock?
Expand Down Expand Up @@ -156,6 +162,17 @@ class RCTAcceleratedCheckoutButtonsView: UIView {
hostingController?.view.frame = bounds
}

// Deprecated in iOS 17 — superseded by registerForTraitChanges in setupView().
// Remove this override when dropping iOS 16 support.
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if #unavailable(iOS 17.0) {
if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
updateView()
}
}
}

override var intrinsicContentSize: CGSize {
let height = calculateRequiredHeight()
return CGSize(width: UIView.noIntrinsicMetric, height: height)
Expand All @@ -172,6 +189,14 @@ class RCTAcceleratedCheckoutButtonsView: UIView {

updateView()

// Replaces traitCollectionDidChange for iOS 17+.
// When dropping iOS 16 support, remove the traitCollectionDidChange override above.
if #available(iOS 17.0, *) {
registerForTraitChanges([UITraitUserInterfaceStyle.self]) { [weak self] (_: RCTAcceleratedCheckoutButtonsView, _: UITraitCollection) in
self?.updateView()
}
}

// Listen for configuration updates
NotificationCenter.default.addObserver(
self,
Expand Down Expand Up @@ -207,7 +232,7 @@ class RCTAcceleratedCheckoutButtonsView: UIView {
updateView()
}

private func attachModifiers(to buttons: AcceleratedCheckoutButtons, wallets: [Wallet]?, applePayLabel: PayWithApplePayButtonLabel?) -> AcceleratedCheckoutButtons {
private func attachModifiers(to buttons: AcceleratedCheckoutButtons, wallets: [Wallet]?, applePayLabel: PayWithApplePayButtonLabel?, applePayStyle: PayWithApplePayButtonStyle) -> AcceleratedCheckoutButtons {
var modifiedButtons = buttons

if let wallets {
Expand All @@ -218,6 +243,8 @@ class RCTAcceleratedCheckoutButtonsView: UIView {
modifiedButtons = modifiedButtons.applePayLabel(applePayLabel)
}

modifiedButtons = modifiedButtons.applePayStyle(applePayStyle)

if let cornerRadius {
modifiedButtons = modifiedButtons.cornerRadius(CGFloat(cornerRadius.doubleValue))
}
Expand Down Expand Up @@ -276,18 +303,20 @@ class RCTAcceleratedCheckoutButtonsView: UIView {
return
}

// Attach modifiers (wallets, applePayLabel, cornerRadius)
buttons = attachModifiers(to: buttons, wallets: shopifyWallets, applePayLabel: PayWithApplePayButtonLabel.from(applePayLabel))
// Attach modifiers (wallets, applePayLabel, applePayStyle, cornerRadius)
buttons = attachModifiers(to: buttons, wallets: shopifyWallets, applePayLabel: PayWithApplePayButtonLabel.from(applePayLabel), applePayStyle: PayWithApplePayButtonStyle.from(applePayStyle))
// Attach event handlers
buttons = attachEventListeners(to: buttons)

var view: AnyView

let colorScheme: SwiftUI.ColorScheme = traitCollection.userInterfaceStyle == .dark ? .dark : .light

// Attach config (and Apple Pay config if available)
if let applePayConfig = AcceleratedCheckoutConfiguration.shared.applePayConfiguration {
view = AnyView(buttons.environmentObject(config).environmentObject(applePayConfig))
view = AnyView(buttons.environmentObject(config).environmentObject(applePayConfig).environment(\.colorScheme, colorScheme))
} else {
view = AnyView(buttons.environmentObject(config))
view = AnyView(buttons.environmentObject(config).environment(\.colorScheme, colorScheme))
}

if let hostingController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ @interface RCT_EXTERN_MODULE (RCTAcceleratedCheckoutButtonsManager, RCTViewManag
*/
RCT_EXPORT_VIEW_PROPERTY(applePayLabel, NSString*)

/**
* Style variant for the Apple Pay button (e.g., "automatic", "black", "white", "whiteOutline").
*/
RCT_EXPORT_VIEW_PROPERTY(applePayStyle, NSString*)

/**
* Emitted when checkout fails. Payload contains a CheckoutException-like shape.
*/
Expand Down
2 changes: 1 addition & 1 deletion modules/@shopify/checkout-sheet-kit/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@shopify/checkout-sheet-kit",
"license": "MIT",
"version": "3.7.0",
"version": "3.8.0",
"main": "lib/commonjs/index.js",
"types": "src/index.ts",
"source": "src/index.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ export enum ApplePayLabel {
topUp = 'topUp',
}

export enum ApplePayStyle {
automatic = 'automatic',
black = 'black',
white = 'white',
whiteOutline = 'whiteOutline',
}

type CheckoutIdentifier =
| {
cartId: string;
Expand All @@ -87,6 +94,12 @@ interface CommonAcceleratedCheckoutButtonsProps {
*/
applePayLabel?: ApplePayLabel;

/**
* Style for the Apple Pay button color
* Defaults to 'automatic' which adapts to the current appearance (light/dark mode)
*/
applePayStyle?: ApplePayStyle;

/**
* Called when checkout fails
*/
Expand Down Expand Up @@ -148,6 +161,7 @@ export type AcceleratedCheckoutButtonsProps = (CartProps | VariantProps) &

interface NativeAcceleratedCheckoutButtonsProps {
applePayLabel?: string;
applePayStyle?: string;
style?: ViewStyle;
checkoutIdentifier: CheckoutIdentifier;
cornerRadius?: number;
Expand Down Expand Up @@ -193,6 +207,7 @@ export const AcceleratedCheckoutButtons: React.FC<
AcceleratedCheckoutButtonsProps
> = ({
applePayLabel,
applePayStyle,
cornerRadius,
wallets,
onFail,
Expand Down Expand Up @@ -307,6 +322,7 @@ export const AcceleratedCheckoutButtons: React.FC<
return (
<RCTAcceleratedCheckoutButtons
applePayLabel={applePayLabel}
applePayStyle={applePayStyle}
style={{...defaultStyles, height: dynamicHeight}}
checkoutIdentifier={checkoutIdentifier}
cornerRadius={cornerRadius}
Expand Down
3 changes: 2 additions & 1 deletion modules/@shopify/checkout-sheet-kit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import {
import {CheckoutErrorCode} from './errors.d';
import type {CheckoutCompletedEvent} from './events.d';
import type {CustomEvent, PixelEvent, StandardEvent} from './pixels.d';
import {ApplePayLabel} from './components/AcceleratedCheckoutButtons';
import {ApplePayLabel, ApplePayStyle} from './components/AcceleratedCheckoutButtons';
import type {
AcceleratedCheckoutButtonsProps,
RenderStateChangeEvent,
Expand Down Expand Up @@ -515,6 +515,7 @@ export {
AcceleratedCheckoutWallet,
ApplePayContactField,
ApplePayLabel,
ApplePayStyle,
ColorScheme,
LogLevel,
ShopifyCheckoutSheet,
Expand Down
Loading
Loading