Skip to content
TokenFlight SDK

Vue

Live project Open in StackBlitz
components/PaymentWidget.vue
<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>
components/ReceiveWidget.vue
<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>
components/PaymentWidgetWithAdapter.vue
<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>

For Nuxt, either use <ClientOnly> or name the file .client.vue:

pages/payment.vue
<template>
<ClientOnly>
<PaymentWidget theme="dark" />
</ClientOnly>
</template>
<script setup>
import PaymentWidget from '~/components/PaymentWidget.vue';
</script>

See SSR Guide for more Nuxt patterns.

Vue has excellent Web Component support. You can use the custom HTML tags directly in templates after registering the elements:

<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>
<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>

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>
ImperativeDeclarative
Wallet adapterPass via constructorPass via registerWidgetElement()
CallbacksPass via constructorPass via registerWidgetElement()
Custom colorsPass in configUse ref + setCustomColors()
SimplicityMore boilerplateCleaner templates
FlexibilityFull controlLimited to HTML attributes

Use declarative for simple embeds with string-only config. Use imperative when you need wallet adapters, callbacks, or dynamic configuration.

  • Use onMounted to initialize — the container must be in the DOM
  • Call destroy() in onBeforeUnmount — 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