Next.js
Live project Open in StackBlitz
App Router (Recommended)
Section titled “App Router (Recommended)”Create a client component for the widget:
'use client';
import { useEffect, useRef, useMemo } from 'react';import type { Config } from '@wagmi/core';import { TokenFlightWidget } from '@tokenflight/swap';import { WagmiWalletAdapter } from '@tokenflight/adapter-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: { toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, amount: '100', tradeType: 'EXACT_OUTPUT', theme, }, walletAdapter, callbacks: { onSwapSuccess: (data) => { console.log('Payment completed!', data.orderId, data.txHash); }, onSwapError: (error) => { console.error(`[${error.code}] ${error.message}`); }, }, });
widget.initialize(); return () => widget.destroy(); }, [walletAdapter, theme]);
return <div ref={containerRef} style={{ minHeight: 560 }} />;}Use it in a server or client page:
import { PaymentWidget } from '../../components/PaymentWidget';import { wagmiConfig } from '../../lib/wagmi';
export default function PaymentPage() { return ( <main> <h1>Payment</h1> <PaymentWidget wagmiConfig={wagmiConfig} /> </main> );}wagmi Configuration
Section titled “wagmi Configuration”import { createConfig, http } from '@wagmi/core';import { mainnet, base, arbitrum } from '@wagmi/core/chains';import { injected } from 'wagmi/connectors';
export const wagmiConfig = createConfig({ chains: [mainnet, base, arbitrum], connectors: [injected()], transports: { [mainnet.id]: http(), [base.id]: http(), [arbitrum.id]: http(), },});Pages Router
Section titled “Pages Router”Use next/dynamic with ssr: false:
import dynamic from 'next/dynamic';
const PaymentWidget = dynamic( () => import('../components/PaymentWidget').then((mod) => mod.PaymentWidget), { ssr: false, loading: () => <div style={{ minHeight: 560 }}>Loading...</div> });
export default function PaymentPage() { return ( <main> <h1>Payment</h1> <PaymentWidget wagmiConfig={wagmiConfig} /> </main> );}Without a Wallet Adapter
Section titled “Without a Wallet Adapter”If your Next.js app already manages wallet connections (via RainbowKit, ConnectKit, etc.), use the widget without an adapter:
'use client';
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: { toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, amount: '100', tradeType: 'EXACT_OUTPUT', theme: 'dark', }, callbacks: { onConnectWallet: () => { // Trigger your existing wallet connection UI document.querySelector('[data-connect-wallet]')?.click(); }, onSwapSuccess: (data) => { console.log('Payment completed:', data); }, }, });
widget.initialize(); return () => widget.destroy(); }, []);
return <div ref={containerRef} style={{ minHeight: 560 }} />;}Key Points
Section titled “Key Points”- Always use
'use client'for components that reference@tokenflight/swap - Use
useReffor the container — avoids React re-render conflicts with Shadow DOM - Cache
walletAdapterwithuseMemo— prevents reconnection on re-renders - Call
destroy()in theuseEffectcleanup — cleans up the Shadow DOM on unmount - See React Integration for more patterns and TypeScript setup