From fd0dd59171435ec9a3f4ab850df727c18ffc48ee Mon Sep 17 00:00:00 2001 From: cskillingstad-stripe <109318264+cskillingstad-stripe@users.noreply.github.com> Date: Tue, 14 Jul 2026 13:15:37 -0700 Subject: [PATCH] Add Terms Element (#691) --- package.json | 2 +- src/checkout/index.ts | 10 +++++++ src/checkout/types/index.ts | 10 +++++++ src/components/createElementComponent.tsx | 5 ++++ src/index.ts | 10 +++++++ src/types/index.ts | 34 +++++++++++++++++++++++ test/mocks.js | 7 +++++ yarn.lock | 8 +++--- 8 files changed, 81 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5d061c5f..e3e7d29a 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@storybook/react": "^6.5.0-beta.8", - "@stripe/stripe-js": "^9.9.0", + "@stripe/stripe-js": "^9.10.0", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.1.1", "@testing-library/react-hooks": "^8.0.0", diff --git a/src/checkout/index.ts b/src/checkout/index.ts index cebaf5a1..029be270 100644 --- a/src/checkout/index.ts +++ b/src/checkout/index.ts @@ -24,6 +24,7 @@ import { ExpressCheckoutElementComponent, TaxIdElementComponent, ContactDetailsElementComponent, + TermsElementComponent, } from './types'; export const CurrencySelectorElement: CurrencySelectorElementComponent = createElementComponent( @@ -74,3 +75,12 @@ export const ShippingAddressElement: ShippingAddressElementComponent = (( const merged = {...options, mode: 'shipping'}; return React.createElement(AddressElementBase, {...rest, options: merged}); }) as ShippingAddressElementComponent; + +/** + * Requires beta access: + * Contact [Stripe support](https://support.stripe.com/) for more information. + */ +export const TermsElement: TermsElementComponent = createElementComponent( + 'terms', + isServer +); diff --git a/src/checkout/types/index.ts b/src/checkout/types/index.ts index 5ec4dd1b..8122d947 100644 --- a/src/checkout/types/index.ts +++ b/src/checkout/types/index.ts @@ -106,3 +106,13 @@ export interface ContactDetailsElementProps extends ElementProps { export type ContactDetailsElementComponent = FunctionComponent< ContactDetailsElementProps >; + +export interface TermsElementProps extends ElementProps { + options?: stripeJs.StripeCheckoutTermsElementOptions; + onReady?: (element: stripeJs.StripeTermsElement) => any; + onEscape?: () => any; + onLoadError?: (event: {elementType: 'terms'; error: StripeError}) => any; + onLoaderStart?: (event: {elementType: 'terms'}) => any; +} + +export type TermsElementComponent = FunctionComponent; diff --git a/src/components/createElementComponent.tsx b/src/components/createElementComponent.tsx index a2f9ff33..c2fc3152 100644 --- a/src/components/createElementComponent.tsx +++ b/src/components/createElementComponent.tsx @@ -183,6 +183,11 @@ const createElementComponent = ( case 'contactDetails': newElement = elementsSdk.createContactDetailsElement(); break; + case 'terms': + newElement = elementsSdk.createTermsElement( + options as stripeJs.StripeCheckoutTermsElementOptions + ); + break; default: throw new Error( `<${displayName}> is not supported inside a checkout provider. Use an provider instead.` diff --git a/src/index.ts b/src/index.ts index 0b55f9c3..6e38e125 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,7 @@ import { PaymentMethodMessagingElementComponent, TaxIdElementComponent, CurrencySelectorElementComponent, + TermsElementComponent, } from './types'; import {isServer} from './utils/isServer'; @@ -206,3 +207,12 @@ export const IssuingCardCopyButtonElement: IssuingCardCopyButtonElementComponent 'issuingCardCopyButton', isServer ); + +/** + * Requires beta access: + * Contact [Stripe support](https://support.stripe.com/) for more information. + */ +export const TermsElement: TermsElementComponent = createElementComponent( + 'terms', + isServer +); diff --git a/src/types/index.ts b/src/types/index.ts index 35ff89be..9bb3008a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -936,3 +936,37 @@ export interface IssuingCardCopyButtonElementProps extends ElementProps { export type IssuingCardCopyButtonElementComponent = FunctionComponent< IssuingCardCopyButtonElementProps >; + +/** + * Requires beta access: + * Contact [Stripe support](https://support.stripe.com/) for more information. + */ +export interface TermsElementProps extends ElementProps { + /** + * An object containing Element configuration options. + */ + options?: stripeJs.StripeTermsElementOptions; + + /** + * Triggered when the Element is fully rendered and can accept imperative `element.focus()` calls. + * Called with a reference to the underlying [Element instance](https://stripe.com/docs/js/element). + */ + onReady?: (element: stripeJs.StripeTermsElement) => any; + + /** + * Triggered when the escape key is pressed within the Element. + */ + onEscape?: () => any; + + /** + * Triggered when the Element fails to load. + */ + onLoadError?: (event: {elementType: 'terms'; error: StripeError}) => any; + + /** + * Triggered when the [loader](https://stripe.com/docs/js/elements_object/create#stripe_elements-options-loader) UI is mounted to the DOM and ready to be displayed. + */ + onLoaderStart?: (event: {elementType: 'terms'}) => any; +} + +export type TermsElementComponent = FunctionComponent; diff --git a/test/mocks.js b/test/mocks.js index b6d10919..ef0d4fc9 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -116,6 +116,13 @@ export const mockCheckoutSdk = () => { getContactDetailsElement: jest.fn(() => { return elements.contactDetails || null; }), + createTermsElement: jest.fn(() => { + elements.terms = mockElement(); + return elements.terms; + }), + getTermsElement: jest.fn(() => { + return elements.terms || null; + }), on: jest.fn((event, callback) => { if (event === 'change') { diff --git a/yarn.lock b/yarn.lock index aaaaaf5b..974d278b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2424,10 +2424,10 @@ regenerator-runtime "^0.13.7" resolve-from "^5.0.0" -"@stripe/stripe-js@^9.9.0": - version "9.9.0" - resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-9.9.0.tgz#47cbf1cab003e52b3fe2acfecc703090fcd00bda" - integrity sha512-Vwqe6Q5cU4i82tPyAv2BpaW/fQSNdOSO4/J8EeDLPp5/oIZiMmdB+Hgh863zFH+rtoxpuWGvD1L7QPh8k1Rdvw== +"@stripe/stripe-js@^9.10.0": + version "9.10.0" + resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-9.10.0.tgz#58f73aae3d07685f39870def2c94daca47684aec" + integrity sha512-rxkKgWLAWtjvJhqEynPJ5zPXoKx5cK4eIUunnMGxwUJDRHKv3MlpA1mCCXdeiXzui5YZNWJKUJBTpe7m30jhOA== "@testing-library/dom@^8.5.0": version "8.13.0"