> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Vue Integration

> Use Voltaire with Vue 3 and composables

<Warning>
  **Looking for Contributors!** This Skill needs an implementation.

  Contributing a Skill involves:

  1. Writing a reference implementation with full functionality
  2. Adding comprehensive tests
  3. Writing documentation with usage examples

  See the [react-query Skill](/skills/react-query) for an example of a framework integration Skill.

  Interested? Open an issue or PR at [github.com/evmts/voltaire](https://github.com/evmts/voltaire).
</Warning>

<Info>
  **Skill** — Copyable reference implementation. Use as-is or customize. See [Skills Philosophy](/concepts/skills).
</Info>

Vue 3 composables for Ethereum development. Similar to the [react-query Skill](/skills/react-query) but using Vue's reactivity system.

## Planned Implementation

### Composables

```typescript theme={null}
// useProvider.ts
import { ref, shallowRef, onMounted, onUnmounted } from 'vue';
import { BrowserProvider } from './BrowserProvider.js';

export function useProvider() {
  const provider = shallowRef(null);
  const accounts = ref([]);
  const chainId = ref(null);
  const isConnected = computed(() => accounts.value.length > 0);

  onMounted(() => {
    try {
      provider.value = BrowserProvider();
      provider.value.getAccounts().then(a => accounts.value = a);
      provider.value.getChainId().then(c => chainId.value = c);

      provider.value.onAccountsChanged(a => accounts.value = a);
      provider.value.onChainChanged(c => chainId.value = c);
    } catch (e) {
      // No provider available
    }
  });

  async function connect() {
    accounts.value = await provider.value?.requestAccounts();
  }

  return { provider, accounts, chainId, isConnected, connect };
}
```

### useBalance

```typescript theme={null}
import { ref, watch, computed } from 'vue';

export function useBalance(address, options = {}) {
  const data = ref(null);
  const isLoading = ref(false);
  const error = ref(null);

  const { provider } = useProvider();

  async function fetch() {
    if (!address.value || !provider.value) return;
    isLoading.value = true;
    try {
      data.value = await provider.value.getBalance(address.value);
      error.value = null;
    } catch (e) {
      error.value = e;
    } finally {
      isLoading.value = false;
    }
  }

  watch([address, provider], fetch, { immediate: true });

  // Auto-refresh on new blocks
  if (options.watch) {
    // Set up block subscription
  }

  return { data, isLoading, error, refetch: fetch };
}
```

### useContractRead

```typescript theme={null}
export function useContractRead({ address, abi, functionName, args }) {
  const data = ref(null);
  const isLoading = ref(false);
  const error = ref(null);

  const { provider } = useProvider();

  async function fetch() {
    if (!provider.value) return;
    isLoading.value = true;
    try {
      const contract = Contract({ address, abi, provider: provider.value });
      data.value = await contract.read[functionName](...(args.value || []));
      error.value = null;
    } catch (e) {
      error.value = e;
    } finally {
      isLoading.value = false;
    }
  }

  watch([args], fetch, { immediate: true, deep: true });

  return { data, isLoading, error, refetch: fetch };
}
```

### useContractWrite

```typescript theme={null}
export function useContractWrite({ address, abi, functionName }) {
  const isLoading = ref(false);
  const error = ref(null);
  const txHash = ref(null);

  const { provider } = useProvider();

  async function write(...args) {
    isLoading.value = true;
    try {
      const contract = Contract({ address, abi, provider: provider.value });
      txHash.value = await contract.write[functionName](...args);
      error.value = null;
      return txHash.value;
    } catch (e) {
      error.value = e;
      throw e;
    } finally {
      isLoading.value = false;
    }
  }

  return { write, isLoading, error, txHash };
}
```

## Example Component

```vue theme={null}
<script setup>
import { useProvider, useBalance, useContractRead } from './composables';

const { accounts, isConnected, connect } = useProvider();
const { data: balance, isLoading: balanceLoading } = useBalance(
  computed(() => accounts.value[0])
);

const { data: tokenBalance } = useContractRead({
  address: USDC_ADDRESS,
  abi: ERC20_ABI,
  functionName: 'balanceOf',
  args: computed(() => [accounts.value[0]])
});
</script>

<template>
  <div v-if="!isConnected">
    <button @click="connect">Connect Wallet</button>
  </div>
  <div v-else>
    <p>Account: {{ accounts[0] }}</p>
    <p>Balance: {{ balance }} ETH</p>
    <p>USDC: {{ tokenBalance }}</p>
  </div>
</template>
```

## Related

* [react-query](/skills/react-query) — React integration
* [eip1193-provider](/skills/eip1193-provider) — Browser wallet connection
* [ethers-contract](/skills/ethers-contract) — Contract interactions
