React Integration
TokenFlight is exposed publicly as <tokenflight-widget> plus the TokenFlightWidget imperative class.
Imperative API
Section titled “Imperative API”The imperative API is the most reliable approach across React versions. Use useRef for the container and useEffect for lifecycle management:
import { useEffect, useRef, useMemo } from 'react';import { TokenFlightWidget } from '@tokenflight/swap';import { WagmiWalletAdapter } from '@tokenflight/adapter-wagmi';
function PaymentWidget({ wagmiConfig, theme = 'dark' }) { 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: { toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, tradeType: 'EXACT_OUTPUT', amount: '100', theme, }, walletAdapter, callbacks: { onSwapSuccess: (data) => console.log('Payment completed:', data.orderId), onSwapError: (error) => console.error(`[${error.code}] ${error.message}`), }, });
widget.initialize(); return () => widget.destroy(); }, [walletAdapter, theme]);
return <div ref={containerRef} style={{ minHeight: 560 }} />;}Declarative Usage
Section titled “Declarative Usage”If you prefer the custom element directly, register the widget once and use <tokenflight-widget> in JSX:
import { useEffect } from 'react';import { registerWidgetElement } from '@tokenflight/swap/widget';import { WagmiWalletAdapter } from '@tokenflight/adapter-wagmi';
function App({ wagmiConfig }) { useEffect(() => { registerWidgetElement({ walletAdapter: new WagmiWalletAdapter(wagmiConfig), callbacks: { onSwapSuccess: (data) => console.log('Payment completed:', data.orderId), onSwapError: (error) => console.error(`[${error.code}] ${error.message}`), }, }); }, [wagmiConfig]);
return ( <tokenflight-widget to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100" theme="dark" /> );}For per-instance callbacks, use a ref:
import { useEffect, useRef } from 'react';import { registerWidgetElement } from '@tokenflight/swap/widget';
registerWidgetElement();
function WidgetWithCallbacks() { const ref = useRef<HTMLElement>(null);
useEffect(() => { if (!ref.current) return; ref.current.__callbacks = { onSwapSuccess: (data) => console.log('Done:', data), onConnectWallet: () => myWalletModal.open(), }; }, []);
return ( <tokenflight-widget ref={ref} to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100" theme="dark" /> );}React JSX Caveats
Section titled “React JSX Caveats”In React 18 and earlier, custom-element props are usually serialized as attributes:
- Objects cannot be passed via JSX.
- Functions cannot be passed via JSX.
- String and boolean HTML attributes work normally.
That is why declarative usage relies on registerWidgetElement() defaults or ref.__callbacks for non-string values.
TypeScript JSX Declarations
Section titled “TypeScript JSX Declarations”Add one import to get typed JSX tags for <tokenflight-widget>:
import "@tokenflight/swap/custom-elements";Key Reminders
Section titled “Key Reminders”- Cache adapter instances with
useMemo. - Call
destroy()in the cleanup function. - Recreate the widget when config changes after
initialize(). - There is no separate React wrapper package; use the public widget directly.