Connect Wallet Menu
This guide demonstrates one approach to building a wallet connection interface using use-wallet. Being a headless library, use-wallet gives you complete control over your wallet UI implementation - you're free to design the interface that best suits your application's needs.
A Simple Pattern
One straightforward approach is to implement a wallet menu with two distinct states:
Disconnected State: Shows a list of available wallets to choose from
Connected State: Shows details and controls for a single active wallet
While use-wallet supports connecting multiple wallets simultaneously, focusing on a single active wallet can:
Simplify the user experience
Reduce complexity in state management
Make edge cases easier to handle
Help avoid potential conflicts between certain wallet providers
This is just one possible pattern - the library's flexible design allows you to implement whatever interface makes sense for your application.
Basic Implementation
Here's a simple implementation that follows this pattern:
import { useWallet, type Wallet } from '@txnlab/use-wallet-react'
import { useState } from 'react'
const WalletMenu = () => {
const { wallets, activeWallet } = useWallet()
// If we have an active wallet, show the connected view
if (activeWallet) {
return <ConnectedWallet wallet={activeWallet} />
}
// Otherwise, show the wallet selection list
return <WalletList wallets={wallets} />
}
const WalletList = ({ wallets }: { wallets: Wallet[] }) => {
return (
<div className="wallet-list">
<h3>Connect Wallet</h3>
<div className="wallet-options">
{wallets.map((wallet) => (
<WalletOption
key={wallet.id}
wallet={wallet}
/>
))}
</div>
</div>
)
}
const WalletOption = ({ wallet }: { wallet: Wallet }) => {
const [connecting, setConnecting] = useState(false)
const handleConnect = async () => {
setConnecting(true)
try {
await wallet.connect()
} catch (error) {
console.error('Failed to connect:', error)
} finally {
setConnecting(false)
}
}
return (
<button
onClick={handleConnect}
disabled={connecting}
className="wallet-option"
>
<img
src={wallet.metadata.icon}
alt={wallet.metadata.name}
width={32}
height={32}
/>
<span>{wallet.metadata.name}</span>
</button>
)
}
const ConnectedWallet = ({ wallet }: { wallet: Wallet }) => {
return (
<div className="connected-wallet">
{/* Wallet header */}
<div className="wallet-header">
<img
src={wallet.metadata.icon}
alt={wallet.metadata.name}
width={32}
height={32}
/>
<span>{wallet.metadata.name}</span>
</div>
{/* Account selector */}
{wallet.accounts.length > 1 && (
<select
value={wallet.activeAccount?.address}
onChange={(e) => wallet.setActiveAccount(e.target.value)}
>
{wallet.accounts.map((account) => (
<option key={account.address} value={account.address}>
{account.name}
</option>
))}
</select>
)}
{/* Account details */}
{wallet.activeAccount && (
<div className="account-info">
<span>{wallet.activeAccount.name}</span>
<span>{wallet.activeAccount.address}</span>
</div>
)}
{/* Disconnect button */}
<button onClick={wallet.disconnect}>
Disconnect
</button>
</div>
)
}
Error Handling and Loading States
Here's how to implement basic error handling and loading states for wallet interactions:
const WalletOption = ({ wallet }: { wallet: Wallet }) => {
const [status, setStatus] = useState('idle')
const handleConnect = async () => {
setStatus('connecting')
try {
await wallet.connect()
setStatus('connected')
} catch (error) {
setStatus('error')
showNotification('Failed to connect wallet')
console.error('Connection error:', error)
}
}
return (
<button
onClick={handleConnect}
disabled={status === 'connecting'}
>
{status === 'connecting' ? 'Connecting...' : 'Connect'}
</button>
)
}
Accessibility
Ensure your wallet menu is accessible:
<div
role="dialog"
aria-labelledby="wallet-menu-title"
className="wallet-menu"
>
<h2 id="wallet-menu-title">
{activeWallet ? 'Connected Wallet' : 'Connect Wallet'}
</h2>
{/* Menu content */}
</div>
Next Steps
Add styling to match your application's design
Implement a modal/dropdown container for the menu
Add balance display for active account
Optional: Add network selection (see Switching Networks)
See Also
Last updated