React Integration
Use the imperative TokenFlightWidget class in React. It works well with useEffect, cleanup, callbacks, and wallet adapters.
Should you read this?
Read this page if your app uses React or Next.js and you need a production pattern.
If you only need a plain HTML example, start with Getting Started. If you are still choosing between APIs, read Choose your API.
Why React should use the class
React can render custom elements, but React 18 and older turn object props and function props into HTML attributes. That means config objects, callbacks, and wallet adapters can be lost.
The class avoids that problem:
- Create the widget in
useEffect. - Pass real objects and functions.
- Destroy the widget during cleanup.
- Recreate it when reactive config changes.
Basic component
This renders the widget and callbacks. Add a wallet adapter before users make crypto payments.
import { useEffect, useRef } from 'react';
import { TokenFlightWidget } from '@tokenflight/swap';
export function PaymentWidget() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!containerRef.current) return;
const widget = new TokenFlightWidget({
container: containerRef.current,
config: {
theme: 'dark',
toToken: {
chainId: 8453,
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
},
tradeType: 'EXACT_OUTPUT',
amount: '100',
},
callbacks: {
onDepositSuccess: (data) => {
console.log('Payment complete:', data.orderId);
},
onDepositError: (error) => {
console.error(`[${error.code}] ${error.message}`);
},
},
});
widget.initialize();
return () => widget.destroy();
}, []);
return <div ref={containerRef} style={{ minHeight: 560 }} />;
}With a wallet adapter
Cache the adapter with useMemo. This prevents wallet reconnection on every render.
import { useEffect, useMemo, useRef } from 'react';
import { TokenFlightWidget } from '@tokenflight/swap';
import { WagmiWalletAdapter } from '@tokenflight/adapter-wagmi';
import type { Config } from 'wagmi';
interface PaymentWidgetProps {
wagmiConfig: Config;
theme?: 'light' | 'dark' | 'auto';
}
export function PaymentWidget({ wagmiConfig, theme = 'dark' }: PaymentWidgetProps) {
const containerRef = useRef<HTMLDivElement>(null);
const walletAdapter = useMemo(
() => new WagmiWalletAdapter(wagmiConfig),
[wagmiConfig],
);
useEffect(() => {
if (!containerRef.current) return;
const widget = new TokenFlightWidget({
container: containerRef.current,
config: {
theme,
toToken: {
chainId: 8453,
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
},
tradeType: 'EXACT_OUTPUT',
amount: '100',
},
walletAdapter,
callbacks: {
onDepositSuccess: (data) => {
console.log('Payment complete:', data.orderId);
},
onDepositError: (error) => {
console.error(`[${error.code}] ${error.message}`);
},
},
});
widget.initialize();
return () => {
widget.destroy();
walletAdapter.destroy?.();
};
}, [theme, walletAdapter]);
return <div ref={containerRef} style={{ minHeight: 560 }} />;
}When config changes
initialize() runs once. If theme, amount, toToken, or the wallet adapter changes, include those values in the dependency list. React will run cleanup, destroy the old widget, and create a new one.
Do not mutate the widget config after initialize(). Recreate the widget instead.
TypeScript JSX support
If you still render <tokenflight-widget> in JSX, add the type import in a declaration file so it is not emitted as runtime JavaScript:
import '@tokenflight/swap/custom-elements';This adds typed custom element attributes. It does not register the element at runtime and does not change the runtime recommendation above.
Next step
- Building with Next.js? Read Next.js.
- Need wallet setup details? Read Custom Wallet Adapter.
- Need callbacks and errors? Read Events & Callbacks and Error Handling.
- Need payment proof? Read Backend Verification.