Element Library

The Schematic Components library provides several advanced features for customizing and extending the default behavior.

Launch Checkout Programmatically

A common billing use case is to present a user with a paywall, and then open a checkout flow to quickly allow them to upgrade their plan. If you need to show the user’s current plan name in the paywall (e.g. “You’re on the Free plan”), the React and Vue SDKs provide that data directly. See the React SDK docs or Vue SDK docs for details.

Imagine a user is trying to create their 6th AI-generated image, but their current plan only includes 5 images per month. You can present them a paywall explaining they are at their limit and prove an “Upgrade to the Pro Plan” button. When they click the upgrade button, you can create a seamless upgrade experience by:

  1. Opening the checkout flow
  2. Pre-selecting the Pro plan they need to upgrade to

Here’s a barebones implementation of this:

1"use client"
2
3import {
4 CheckoutDialog,
5 EmbedProvider,
6 useEmbed,
7} from "@schematichq/schematic-components";
8import { useEffect, useCallback } from "react";
9
10const PLAN_ID = ""; // plan to be preselected
11
12function Checkout() {
13 const { initializeWithPlan, layout, setAccessToken, stale, hydrate } = useEmbed();
14 const checkout = useCallback(async () => {
15 const response = await fetch("/api/accessToken");
16 const result = await response.json();
17 setAccessToken(result.accessToken);
18 initializeWithPlan({ planId: PLAN_ID });
19 }, [setAccessToken, initializeWithPlan]);
20
21 // this is necessary when launching straight to checkout
22 useEffect(() => {
23 if (stale) {
24 hydrate();
25 }
26 }, [stale, hydrate]);
27
28 return (
29 <>
30 <button onClick={checkout}>Upgrade to Pro</button>
31 {layout === "checkout" && createPortal(<CheckoutDialog />, document.body)}
32 </>
33 )
34}
35
36export default function CustomCheckout() {
37 return (
38 <EmbedProvider>
39 <Checkout />
40 </EmbedProvider>
41 );
42}

The key element is initializeWithPlan, an alternate entry point to the checkout flow. Above, we pass a plan ID to the function, which will pre-select the plan in the checkout flow.

In the above example, while the plan is pre-selected, the user will still be able to navigate the full checkout flow. A common desire is to take the user directly to the payment step, and remove the options to change plan or add on choices. To achieve this, initializeWithPlan can be called with an object of additional options. The full set of options are below.

1const config = {
2 planId: 'plan_abc123', // pre-select a Plan
3 addOnIds: ['plan_addon123'], // pre-select 1 or more add ons
4 skipped: {
5 planStage: true, // if true, skip plan selection
6 addOnStage: true // if true, skip add on selection
7 },
8 hideSkipped: true, // if true, hide skipped stages from breadcrumb navigation
9 startTrialIfAvailable: true // if true (default), start a trial when the plan is trialable and the company is eligible
10};
11
12initializeWithPlan(config);

When the pre-selected plan offers a trial and the company is eligible, initializeWithPlan starts checkout in trial mode by default. This matches the behavior of the in-dialog “Start trial” button, so customers using the bypass flow get the same trial they would have gotten by clicking through the plan stage. Pass startTrialIfAvailable: false to charge immediately instead.

Pre-filling checkout fields

If your application already knows the customer’s billing email or name, you can pre-populate those fields in the checkout payment form so the user does not have to retype them. Pass a checkoutPrefill prop to EmbedProvider:

1<EmbedProvider
2 checkoutPrefill={{
3 billingDetails: {
4 email: "ada@example.com",
5 name: "Ada Lovelace",
6 },
7 }}
8>
9 <Checkout />
10</EmbedProvider>

Pre-filled values are only applied to fields the checkout is configured to collect. The email field appears when email collection is enabled, and the name is part of the billing address form. The user can edit any pre-filled value before submitting, and their edits are never overwritten if the prefill value changes.

Examples

You can see a full example, including error handling and loading states in our example app.

Check it out online: https://schematic-next-example.vercel.app/custom-checkout See the code: https://github.com/SchematicHQ/schematic-next-example/blob/main/src/app/custom-checkout/page.tsx

Reacting to Plan Changes in the Browser

Schematic components dispatch a plan-changed event on the window when a checkout completes, so you can run your own logic after a user subscribes, upgrades, downgrades, or unsubscribes. This includes patterns like redirecting users to a cancellation feedback form after they unsubscribe. See Checkout Flow Events for the event payload and examples.

Collecting Taxes

Schematic supports Stripe Tax (and 3rd party tax providers that integrate with Stripe Tax) to simplify collecting tax and ensuring compliance with tax laws. Components can be configured to collect tax information from the user (e.g. billing address) and generate the correct taxes at checkout.

To enable tax collection, head to “Plans > Configuration”. Scroll down to find Checkout Settings. Here, Stripe Tax can be enabled and the relevant billing information can be set to be collected from the user inside the Schematic Checkout flow.

Stripe Tax Configuration

While checking out, the necessary tax information will be collected from the user while they are inputting their payment method.

Checkout data collection

And finally, taxes will be presented on the final checkout step.

US Taxes

Checkout tax collection

EU Taxes

Checkout tax collection

If you choose to save tax information to Stripe, it will appear on the customer details page in Stripe.

Stripe Customer Details