Frontend Integration with Web3Modal

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Frontend Integration with Web3Modal
Simple
~2-3 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Web3Modal Frontend Integration

If your dApp needs to support multiple wallets, don't build a custom wallet selector from scratch. WalletConnect's Web3Modal v3 solves this: 300+ wallets, WalletConnect QR, mobile deeplinks, email/social login via Web3Auth — all out of the box. The integration challenge is proper config setup and avoiding typical pitfalls with hydration and SSR.

Installation and Basic Configuration

npm install @web3modal/wagmi wagmi viem @tanstack/react-query

Get your Project ID from cloud.walletconnect.com. Without it, the modal will launch, but WalletConnect connections won't work.

// config/web3modal.ts
import { createWeb3Modal } from '@web3modal/wagmi/react'
import { defaultWagmiConfig } from '@web3modal/wagmi/react/config'
import { mainnet, arbitrum, base, polygon } from 'wagmi/chains'

const projectId = import.meta.env.VITE_WC_PROJECT_ID

const metadata = {
  name: 'My dApp',
  description: 'My dApp description',
  url: 'https://mydapp.xyz', // must match the domain in WC Cloud
  icons: ['https://mydapp.xyz/icon.png'],
}

export const config = defaultWagmiConfig({
  chains: [mainnet, arbitrum, base, polygon],
  projectId,
  metadata,
})

createWeb3Modal({
  wagmiConfig: config,
  projectId,
  enableAnalytics: true,
  enableOnramp: true, // built-in fiat on-ramp
  themeMode: 'dark',
  themeVariables: {
    '--w3m-accent': '#7c3aed',
    '--w3m-border-radius-master': '4px',
  },
})

Integration into React Application

// main.tsx
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from './config/web3modal'

const queryClient = new QueryClient()

export function App() {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <Router />
      </QueryClientProvider>
    </WagmiProvider>
  )
}

The connect button is either a ready-made component or custom via a hook:

// Ready-made component
<w3m-button />

// Custom button
import { useWeb3Modal } from '@web3modal/wagmi/react'
import { useAccount } from 'wagmi'

function ConnectWallet() {
  const { open } = useWeb3Modal()
  const { address, isConnected } = useAccount()

  return (
    <button onClick={() => open()}>
      {isConnected ? `${address?.slice(0, 6)}...${address?.slice(-4)}` : 'Connect Wallet'}
    </button>
  )
}

Custom Networks

Adding networks not available in wagmi/chains:

import { defineChain } from 'viem'

const sonic = defineChain({
  id: 146,
  name: 'Sonic',
  nativeCurrency: { name: 'Sonic', symbol: 'S', decimals: 18 },
  rpcUrls: { default: { http: ['https://rpc.soniclabs.com'] } },
  blockExplorers: { default: { name: 'SonicScan', url: 'https://sonicscan.org' } },
})

export const config = defaultWagmiConfig({
  chains: [mainnet, sonic],
  // ...
})

Network Switching

Web3Modal shows a network switcher automatically. For programmatic switching:

import { useWeb3Modal } from '@web3modal/wagmi/react'

const { open } = useWeb3Modal()

// Open directly on the networks tab
<button onClick={() => open({ view: 'Networks' })}>Switch Network</button>

SSR / Next.js

In Next.js App Router, hydration is an issue: Web3Modal initializes client-side, but server rendering doesn't know about the connected wallet. Solution: 'use client' directive for the provider and lazy initialization:

// providers/Web3Provider.tsx
'use client'
import { createWeb3Modal } from '@web3modal/wagmi/react'
import { useEffect, useState } from 'react'

// Initialization outside the component — executes once
createWeb3Modal({ wagmiConfig: config, projectId })

export function Web3Provider({ children }: { children: React.ReactNode }) {
  const [mounted, setMounted] = useState(false)
  useEffect(() => setMounted(true), [])

  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {mounted ? children : null}
      </QueryClientProvider>
    </WagmiProvider>
  )
}

The mounted guard prevents hydration mismatch — without it, React throws a warning about the difference between server and client rendering of the wallet address.

Email and Social Login

Web3Modal supports embedded wallets via Web3Auth. Enable in config:

createWeb3Modal({
  // ...
  featuredWalletIds: [], // remove featured wallets if you want a clean UI
  emailEnabled: true, // email OTP wallet
})

Users log in via email or Google/GitHub — they get a non-custodial wallet. For a broad audience without crypto experience, this significantly reduces the barrier to entry.