Vue
Live projectOpen in StackBlitz
Payment Widget Component
vue
<!-- components/PaymentWidget.vue -->
<template>
<div ref="containerRef" style="min-height: 560px"></div>
</template>
<script setup lang="ts">
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:
vue
<template>
<main>
<h1>Payment</h1>
<PaymentWidget theme="dark" />
</main>
</template>
<script setup>
</script>Widget Component
vue
<!-- components/ReceiveWidget.vue -->
<template>
<div ref="containerRef" style="min-height: 560px"></div>
</template>
<script setup lang="ts">
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:
vue
<template>
<ReceiveWidget
:target-chain-id="8453"
target-address="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
amount="100"
theme="dark"
/>
</template>
<script setup>
</script>With a Wallet Adapter
vue
<!-- components/PaymentWidgetWithAdapter.vue -->
<template>
<div ref="containerRef" style="min-height: 560px"></div>
</template>
<script setup lang="ts">
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
For Nuxt, either use <ClientOnly> or name the file .client.vue:
vue
<!-- pages/payment.vue -->
<template>
<ClientOnly>
<PaymentWidget theme="dark" />
</ClientOnly>
</template>
<script setup>
</script>See SSR Guide for more Nuxt patterns.
Declarative Usage
Vue has excellent Web Component support. You can use the custom HTML tags directly in templates after registering the elements:
Widget (Declarative)
vue
<script setup>
registerWidgetElement();
</script>
<template>
<tokenflight-widget
theme="dark"
locale="en-US"
to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
trade-type="EXACT_OUTPUT"
amount="100"
/>
</template>Widget
vue
<script setup>
registerWidgetElement();
</script>
<template>
<tokenflight-widget
theme="dark"
to-token="eip155:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
trade-type="EXACT_OUTPUT"
amount="100"
/>
</template>With Custom Colors
For runtime methods like setCustomColors(), use a template ref:
vue
<script setup>
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>TIP
Vue's compilerOptions.isCustomElement can suppress unknown-element warnings. Add to vite.config.ts:
ts
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('tokenflight-'),
},
},
})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
- 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