# Wallet Connection UX Best Practices ## Comparison of the Three Main Libraries | Library | Maintainer | Built On | UI Style | Customizability | Recommended Use Case | |----|--------|------|---------|--------|---------| | **RainbowKit** | Rainbow | wagmi | Polished, rainbow aesthetic | Medium | General dApps, fast launch | | **ConnectKit** | Family | wagmi | Clean and modern | High | Brand consistency focused | | **AppKit (Web3Modal v3)** | WalletConnect | wagmi/ethers | Generic | Medium | Multi-chain, multi-ecosystem | | **wagmi native** | wagmi | — | No UI | Fully custom | Full customization needed | --- ## RainbowKit (Least Effort) ```bash npm install @rainbow-me/rainbowkit wagmi viem @tanstack/react-query ``` ```tsx // App.tsx import '@rainbow-me/rainbowkit/styles.css' import { getDefaultConfig, RainbowKitProvider } from '@rainbow-me/rainbowkit' import { WagmiProvider } from 'wagmi' import { mainnet, polygon, base } from 'wagmi/chains' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' const config = getDefaultConfig({ appName: 'My App', projectId: 'YOUR_WALLETCONNECT_PROJECT_ID', // get from cloud.walletconnect.com chains: [mainnet, base, polygon], }) export function App() { return ( ) } // Usage import { ConnectButton } from '@rainbow-me/rainbowkit' // done in one line ``` **Custom ConnectButton:** ```tsx {({ account, chain, openConnectModal, openChainModal, mounted }) => ( )} ``` --- ## ConnectKit (More Customization) ```bash npm install connectkit wagmi viem @tanstack/react-query ``` ```tsx import { ConnectKitProvider, ConnectKitButton, getDefaultConfig } from 'connectkit' const config = createConfig(getDefaultConfig({ walletConnectProjectId: 'YOUR_PROJECT_ID', appName: 'My App', chains: [mainnet, base], })) // Themes: auto | light | dark | web95 | retro | soft | midnight | minimal | rounded | nouns ``` --- ## UX Best Practices ### 1. Show Correct Chain State ```tsx const { chain } = useAccount() const { chains, switchChain } = useSwitchChain() // Detect wrong chain and prompt user to switch if (chain?.id !== expectedChainId) { return } ``` ### 2. ENS Name + Avatar Display ```tsx const { data: ensName } = useEnsName({ address, chainId: mainnet.id }) const { data: avatar } = useEnsAvatar({ name: ensName!, chainId: mainnet.id }) // Show: vitalik.eth instead of 0xd8dA... const displayName = ensName ?? truncateAddress(address) // "0xd8dA...6045" ``` ### 3. Transaction Status Feedback ```tsx const { writeContract, data: hash, isPending } = useWriteContract() const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash }) // Three-phase feedback if (isPending) return Waiting for wallet confirmation... if (isConfirming) return Confirming transaction (0/{targetConfirmations}) if (isSuccess) return ✅ Transaction successful! ``` ### 4. Gas Estimation ```tsx import { useEstimateGas } from 'wagmi' const { data: gasEstimate } = useEstimateGas({ to, data, value }) // Display estimated gas cost ``` ### 5. Mobile Compatibility - RainbowKit supports WalletConnect QR and mobile deep links out of the box - Prioritize MetaMask Mobile / Trust Wallet when a mobile device is detected - iOS Safari note: wallet actions must be triggered by a user gesture (cannot open automatically) ## Common Pitfalls - `projectId` must be obtained from cloud.walletconnect.com — do not use the example ID - ENS lookups only work on Ethereum Mainnet (chainId=1); other chains return null - Do not use wagmi hooks directly in SSR — wrap them inside a client component # Wallet Connection UX Best Practices ## Comparison of the Three Main Libraries | Library | Maintainer | Built On | UI Style | Customizability | Recommended Use Case | |----|--------|------|---------|--------|---------| | **RainbowKit** | Rainbow | wagmi | Polished, rainbow aesthetic | Medium | General dApps, fast launch | | **ConnectKit** | Family | wagmi | Clean and modern | High | Brand consistency focused | | **AppKit (Web3Modal v3)** | WalletConnect | wagmi/ethers | Generic | Medium | Multi-chain, multi-ecosystem | | **wagmi native** | wagmi | — | No UI | Fully custom | Full customization needed | --- ## RainbowKit (Least Effort) ```bash npm install @rainbow-me/rainbowkit wagmi viem @tanstack/react-query ``` ```tsx // App.tsx import '@rainbow-me/rainbowkit/styles.css' import { getDefaultConfig, RainbowKitProvider } from '@rainbow-me/rainbowkit' import { WagmiProvider } from 'wagmi' import { mainnet, polygon, base } from 'wagmi/chains' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' const config = getDefaultConfig({ appName: 'My App', projectId: 'YOUR_WALLETCONNECT_PROJECT_ID', // get from cloud.walletconnect.com chains: [mainnet, base, polygon], }) export function App() { return ( ) } // Usage import { ConnectButton } from '@rainbow-me/rainbowkit' // done in one line ``` **Custom ConnectButton:** ```tsx {({ account, chain, openConnectModal, openChainModal, mounted }) => ( )} ``` --- ## ConnectKit (More Customization) ```bash npm install connectkit wagmi viem @tanstack/react-query ``` ```tsx import { ConnectKitProvider, ConnectKitButton, getDefaultConfig } from 'connectkit' const config = createConfig(getDefaultConfig({ walletConnectProjectId: 'YOUR_PROJECT_ID', appName: 'My App', chains: [mainnet, base], })) // Themes: auto | light | dark | web95 | retro | soft | midnight | minimal | rounded | nouns ``` --- ## UX Best Practices ### 1. Show Correct Chain State ```tsx const { chain } = useAccount() const { chains, switchChain } = useSwitchChain() // Detect wrong chain and prompt user to switch if (chain?.id !== expectedChainId) { return } ``` ### 2. ENS Name + Avatar Display ```tsx const { data: ensName } = useEnsName({ address, chainId: mainnet.id }) const { data: avatar } = useEnsAvatar({ name: ensName!, chainId: mainnet.id }) // Show: vitalik.eth instead of 0xd8dA... const displayName = ensName ?? truncateAddress(address) // "0xd8dA...6045" ``` ### 3. Transaction Status Feedback ```tsx const { writeContract, data: hash, isPending } = useWriteContract() const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ hash }) // Three-phase feedback if (isPending) return Waiting for wallet confirmation... if (isConfirming) return Confirming transaction (0/{targetConfirmations}) if (isSuccess) return ✅ Transaction successful! ``` ### 4. Gas Estimation ```tsx import { useEstimateGas } from 'wagmi' const { data: gasEstimate } = useEstimateGas({ to, data, value }) // Display estimated gas cost ``` ### 5. Mobile Compatibility - RainbowKit supports WalletConnect QR and mobile deep links out of the box - Prioritize MetaMask Mobile / Trust Wallet when a mobile device is detected - iOS Safari note: wallet actions must be triggered by a user gesture (cannot open automatically) ## Common Pitfalls - `projectId` must be obtained from cloud.walletconnect.com — do not use the example ID - ENS lookups only work on Ethereum Mainnet (chainId=1); other chains return null - Do not use wagmi hooks directly in SSR — wrap them inside a client component - Handle chain-switch failures (user rejection) gracefully with a friendly message — don't crash