Skip to main content

Overview

The ConnectButton component is the primary wallet interface for the OneBalance application. It manages user authentication via Privy, displays the connected wallet address, and provides a detailed account modal with portfolio information, balances across chains, and asset management capabilities.

Import

import { ConnectButton } from '@/components/ConnectButton';

Props

The ConnectButton component does not accept any props. It manages its own state and relies on global context providers.
The component requires the following providers to be available in the React tree:
  • PrivyProvider for authentication
  • PredictedAddressContext for account address management

Features

Authentication States

The component handles three distinct states:
  1. Loading State: Displays while Privy is initializing
  2. Unauthenticated State: Shows a “Login” button
  3. Authenticated State: Shows wallet address and opens account modal

Account Modal

When authenticated, clicking the button opens a comprehensive account modal that includes:
  • Wallet Header: Account identifier with formatted address
  • Account Address: Full address display with copy functionality
  • Portfolio Summary: Total portfolio value, asset count, and chain count
  • Asset List: Detailed breakdown of all assets across chains
  • Logout Button: Disconnects the wallet

Usage

Basic Usage

import { Header } from '@/components/Header';
import { ConnectButton } from '@/components/ConnectButton';

export const Header = () => {
  return (
    <header className="flex items-center justify-between p-4">
      <h1>OneBalance</h1>
      <ConnectButton />
    </header>
  );
};

With Onboarding Annotation

<div data-onboarding="connect-button">
  <ConnectButton />
</div>

Component Behavior

Address Formatting

The component automatically formats wallet addresses for display:
  • Full address: 0x1234567890abcdef1234567890abcdef12345678
  • Displayed as: 0x1234...5678
This is handled by the internal formatAddress function:
const formatAddress = (address?: string) => {
  if (!address) return 'Unknown';
  return `${address.slice(0, 6)}...${address.slice(-4)}`;
};

Predicted Address Management

The component automatically fetches the predicted account address when a wallet connects:
useEffect(() => {
  if (authenticated && embeddedWallet && !predictedAddress) {
    getPredictedAddress();
  }
}, [authenticated, embeddedWallet, predictedAddress, getPredictedAddress]);

Balance Refresh

Balances are automatically refreshed when the account modal is opened:
useEffect(() => {
  if (open && predictedAddress) {
    fetchBalances();
  }
}, [open, predictedAddress]);

State Variations

// Shown while Privy is initializing
<Button variant="outline" size="sm" disabled className="animate-pulse">
  <div className="w-4 h-4 bg-gray-300 rounded mr-2"></div>
  Loading...
</Button>

Dependencies

Hooks

usePrivy
hook
Provides authentication methods (login, logout) and state (authenticated, ready)
useEmbeddedWallet
hook
Returns the embedded wallet instance for address derivation
usePredictedAddress
hook
Manages the predicted account address state and fetching
useBalances
hook
Fetches and manages balance data for the connected account
useAssets
hook
Provides asset metadata for display in the asset list

Child Components

The account modal renders several specialized components:
  • AssetList: Detailed asset breakdown by chain
<Dialog open={open} onOpenChange={setOpen}>
  <DialogTrigger asChild>
    {/* Connect button */}
  </DialogTrigger>
  
  <DialogContent className="sm:max-w-lg max-h-[90vh]">
    <div className="space-y-6 overflow-y-auto">
      <WalletHeader address={predictedAddress} />
      <AccountAddress address={predictedAddress} />
      <PortfolioSummary
        totalValue={balances.totalBalance.fiatValue}
        assetCount={balances.balanceByAggregatedAsset.length}
        chainCount={uniqueChainCount}
        onRefresh={fetchBalances}
      />
      <AssetList
        balances={balances.balanceByAggregatedAsset}
        assets={assets}
        loading={balancesLoading}
      />
    </div>
    
    <div className="pt-4 border-t">
      <Button onClick={logout}>Logout</Button>
    </div>
  </DialogContent>
</Dialog>

Styling

The component uses Tailwind CSS classes for styling with support for dark mode:
  • Connected indicator: bg-emerald-500 animate-pulse (pulsing green dot)
  • Button hover effects: hover:shadow-md transition-all duration-200
  • Login button: shadow-lg hover:shadow-xl transform hover:scale-105

Accessibility

  • Includes a hidden DialogTitle for screen readers
  • Proper button semantics with aria-label attributes
  • Keyboard navigation support through Dialog component
  • Focus management when modal opens/closes

Build docs developers (and LLMs) love