Vue
Live project Open in StackBlitz
Payment Widget Component
Section titled “Payment Widget Component”<template> <div ref="containerRef" style="min-height: 560px"></div></template>
<script setup lang="ts">import { ref, onMounted, onBeforeUnmount } from 'vue';import { TokenFlightWidget } from '@tokenflight/swap';import { registerWidgetElement } from '@tokenflight/swap/widget';
const props = defineProps<{ theme?: 'light' | 'dark' | 'auto';}>();
const containerRef = ref<HTMLDivElement>();let widget: TokenFlightWidget | null = null;
registerWidgetElement();
onMounted(() => { if (!containerRef.value) return;
widget = new TokenFlightWidget({ container: containerRef.value, config: { toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, amount: '100', tradeType: 'EXACT_OUTPUT', theme: props.theme ?? 'dark', }, callbacks: { onSwapSuccess: (data) => { console.log('Payment completed:', data.orderId, data.txHash); }, onSwapError: (error) => { console.error(`[${error.code}] ${error.message}`); }, onConnectWallet: () => { // Open your wallet connection modal console.log('Connect wallet requested'); }, }, });
widget.initialize();});
onBeforeUnmount(() => { widget?.destroy(); widget = null;});</script>Usage:
<template> <main> <h1>Payment</h1> <PaymentWidget theme="dark" /> </main></template>
<script setup>import PaymentWidget from './components/PaymentWidget.vue';</script>Widget Component
Section titled “Widget Component”<template> <div ref="containerRef" style="min-height: 560px"></div></template>
<script setup lang="ts">import { ref, onMounted, onBeforeUnmount } from 'vue';import { TokenFlightWidget } from '@tokenflight/swap';import { registerWidgetElement } from '@tokenflight/swap/widget';
const props = defineProps<{ targetChainId: number; targetAddress: string; amount: string; theme?: 'light' | 'dark' | 'auto';}>();
const containerRef = ref<HTMLDivElement>();let receive: TokenFlightWidget | null = null;
registerWidgetElement();
onMounted(() => { if (!containerRef.value) return;
receive = new TokenFlightWidget({ container: containerRef.value, config: { toToken: { chainId: props.targetChainId, address: props.targetAddress, }, amount: props.amount, tradeType: 'EXACT_OUTPUT', theme: props.theme ?? 'dark', }, callbacks: { onSwapSuccess: (data) => { console.log('Payment received:', data); }, onSwapError: (error) => { console.error('Payment error:', error); }, }, });
receive.initialize();});
onBeforeUnmount(() => { receive?.destroy(); receive = null;});</script>Usage:
<template> <ReceiveWidget :target-chain-id="8453" target-address="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" amount="100" theme="dark" /></template>
<script setup>import ReceiveWidget from './components/ReceiveWidget.vue';</script>With a Wallet Adapter
Section titled “With a Wallet Adapter”<template> <div ref="containerRef" style="min-height: 560px"></div></template>
<script setup lang="ts">import { ref, onMounted, onBeforeUnmount } from 'vue';import { TokenFlightWidget } from '@tokenflight/swap';import { EthersWalletAdapter } from '@tokenflight/adapter-ethers';
const containerRef = ref<HTMLDivElement>();let widget: TokenFlightWidget | null = null;
onMounted(() => { if (!containerRef.value || !window.ethereum) return;
const adapter = new EthersWalletAdapter(window.ethereum);
widget = new TokenFlightWidget({ container: containerRef.value, config: { toToken: { chainId: 8453, address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' }, amount: '100', tradeType: 'EXACT_OUTPUT', theme: 'dark', }, walletAdapter: adapter, callbacks: { onSwapSuccess: (data) => console.log('Success:', data), }, });
widget.initialize();});
onBeforeUnmount(() => { widget?.destroy(); widget = null;});</script>Nuxt 3
Section titled “Nuxt 3”For Nuxt, either use <ClientOnly> or name the file .client.vue:
<template> <ClientOnly> <PaymentWidget theme="dark" /> </ClientOnly></template>
<script setup>import PaymentWidget from '~/components/PaymentWidget.vue';</script>See SSR Guide for more Nuxt patterns.
Declarative Usage
Section titled “Declarative Usage”Vue has excellent Web Component support. You can use the custom HTML tags directly in templates after registering the elements:
Widget (Declarative)
Section titled “Widget (Declarative)”<script setup>import { registerWidgetElement } from '@tokenflight/swap/widget';
registerWidgetElement();</script>
<template> <tokenflight-widget theme="dark" locale="en-US" to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100" /></template>Widget
Section titled “Widget”<script setup>import { registerWidgetElement } from '@tokenflight/swap/widget';
registerWidgetElement();</script>
<template> <tokenflight-widget theme="dark" to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100" /></template>With Custom Colors
Section titled “With Custom Colors”For runtime methods like setCustomColors(), use a template ref:
<script setup>import { ref, onMounted } from 'vue';import { registerWidgetElement } from '@tokenflight/swap/widget';
registerWidgetElement();const el = ref(null);
onMounted(() => { el.value?.setCustomColors({ primary: '#FF007A' });});</script>
<template> <tokenflight-widget ref="el" theme="dark" to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" trade-type="EXACT_OUTPUT" amount="100" /></template>When to Use Which
Section titled “When to Use Which”| Imperative | Declarative | |
|---|---|---|
| Wallet adapter | Pass via constructor | Pass via registerWidgetElement() |
| Callbacks | Pass via constructor | Pass via registerWidgetElement() |
| Custom colors | Pass in config | Use ref + setCustomColors() |
| Simplicity | More boilerplate | Cleaner templates |
| Flexibility | Full control | Limited to HTML attributes |
Use declarative for simple embeds with string-only config. Use imperative when you need wallet adapters, callbacks, or dynamic configuration.
Key Points
Section titled “Key Points”- Use
onMountedto initialize — the container must be in the DOM - Call
destroy()inonBeforeUnmount— cleans up the Shadow DOM on unmount - Store the widget instance outside
ref()— it doesn’t need Vue reactivity - For Nuxt, wrap with
<ClientOnly>to avoid SSR issues registerWidgetElement()can be called multiple times safely