Skip to Content
Welcome to RitoSwap's documentation!

Connect Modal

      • ConnectModal.tsx
      • ConnectModal.module.css
      • ConnectButton.tsx

Overview

The Connect Modal serves as the primary gateway for wallet connections within the RitoSwap ecosystem. This modal component provides users with a comprehensive interface for selecting their preferred wallet provider, displaying WalletConnect QR codes for desktop connections, and managing the entire connection flow with visual feedback at each stage. As part of the Wallet UI modal collection, it delivers a polished connection experience that adapts seamlessly between desktop and mobile contexts.

Connect Modal displaying available wallet providers

Inspired by ConnectKit’s clean interface design, the Connect Modal extends beyond standard connection flows with custom branding elements, enhanced mobile workflows, and sophisticated state management. The component leverages Wagmi v2’s wallet detection capabilities combined with EIP-6963 standards to automatically discover and display available wallet providers with their respective logos and names. This modal can be triggered by any component that manages its open state, most commonly through the ConnectButton widget.

Mobile Deep Linking Architecture

The Connect Modal implements a specialized workflow for mobile devices that leverages WalletConnect’s deep linking protocol. When users on mobile browsers initiate a WalletConnect connection, the modal automatically transitions to a connecting state and triggers a deep link that opens the operating system’s app chooser. This allows users to select their preferred mobile wallet app and complete the connection without manual app switching.

WalletConnect Deep Linking Guide

Component Architecture

The Connect Modal demonstrates sophisticated state management that orchestrates multiple connection methods while providing clear visual feedback throughout the user journey. The component creates a portal-based overlay that renders above all other content, ensuring consistent accessibility regardless of the triggering component’s position in the DOM hierarchy.

Triggering Mechanisms

While the Connect Modal itself is a controlled component that responds to external state management, it’s most commonly triggered by the ConnectButton widget. When users click the ConnectButton, it updates its internal state to open the modal:

ConnectButton that triggers the Connect Modal when clicked
// In ConnectButton.tsx const [isConnectModalOpen, setIsConnectModalOpen] = useState(false); // Clicking the button opens the modal <button onClick={() => setIsConnectModalOpen(true)}> Connect Wallet </button> // Modal receives state through props <ConnectModal isOpen={isConnectModalOpen} onClose={() => setIsConnectModalOpen(false)} />

This architecture ensures the modal remains decoupled from its triggers, allowing any component to control its visibility through simple boolean state management.

Wallet Provider Detection

The Connect Modal leverages Wagmi’s connector system enhanced with EIP-6963 provider discovery to automatically detect and display available wallet providers. This modern approach allows wallets to announce themselves to dApps, providing metadata including names and icons without requiring manual configuration:

const { connectors } = useConnect(); // Separate injected wallets from WalletConnect const injectedConnectors = connectors.filter( (c) => c.type === "injected" && c.id !== "injected" ); const walletConnectConnector = connectors.find( (c) => c.type === "walletConnect" );

Each detected wallet provider automatically supplies its branding assets through the connector metadata, eliminating the need for hardcoded wallet information and ensuring the modal always displays current provider details.

Portal Rendering Strategy

The Connect Modal implements React’s portal pattern to ensure proper rendering above all other content:

return createPortal( <> <div className={styles.backdrop} onClick={onClose} /> <div className={styles.modalWrapper}> {/* Modal content */} </div> </>, document.body );

This approach prevents z-index conflicts and ensures the modal always appears above other interface elements, regardless of nested component hierarchies or CSS stacking contexts.

The Connect Modal implements six distinct states, each carefully designed to guide users through the connection process with clear visual feedback and appropriate actions.

Default State - Provider Selection

Default state showing wallet provider options

The default state presents users with a clean interface featuring the RitoSwap logo and available wallet options. Each wallet provider displays with its official icon and name, automatically retrieved through the EIP-6963 standard. The modal includes an educational link for users new to Web3 wallets and displays terms of service acknowledgment in the footer.

WalletConnect QR State (Desktop Only)

WalletConnect QR code display for desktop connections

When desktop users select WalletConnect, the modal transitions to display a customized QR code. The QR implementation uses the react-qr-code library with custom styling that incorporates RitoSwap’s brand colors and embeds the RitoSwap logo in the center:

<QRCode value={qrUri} size={198} bgColor="#000000" fgColor="var(--accent-color)" level="M" />

The modal provides a copy-to-clipboard function for the WalletConnect URI, allowing users to manually share the connection string if needed.

Connecting State

Connecting state with animated feedback

During active connection attempts, the modal displays the selected wallet’s icon with animated loading dots and instructional text. For mobile WalletConnect connections, an “Open Wallet” button appears to re-trigger the deep link if needed. This state persists until the connection succeeds, fails, or the user cancels.

Error State

Error state showing connection failure

Connection failures trigger a brief error state displaying “Connection Unsuccessful” with the wallet icon. The modal automatically returns to the default state after 1.5 seconds, allowing users to retry with a different wallet or troubleshoot the issue.

Canceled State

Canceled state after user rejection

When users explicitly reject a connection request in their wallet, the modal displays a cancellation message. This distinct state helps users understand that the connection wasn’t a technical failure but rather their own action, reducing confusion and support requests.

Get Wallet Educational State

Educational state explaining wallet functionality

New users who click “I don’t have a wallet yet” enter an educational state that explains wallet functionality with clear benefit points. This state includes a prominent call-to-action linking to Ethereum.org’s wallet finder, helping onboard users new to the Web3 ecosystem.

Technical Implementation

Wagmi v2 Hook Integration

The Connect Modal leverages essential Wagmi v2 hooks to manage wallet connections and state:

useConnect provides the core connection functionality, including the list of available connectors, connection initiation, pending states, and error handling. The modal uses these values to orchestrate the entire connection flow.

useAccount monitors the connection status to automatically close the modal upon successful connection, ensuring a smooth user experience without manual intervention.

The connection handler demonstrates careful orchestration of different wallet types:

const handleConnectorClick = useCallback( async (connector: Connector) => { if (connector.type === "walletConnect") { const screenWidth = window.innerWidth; if (screenWidth <= 730) { // Mobile: Direct deep link setModalState("connecting"); const provider = await connector.getProvider(); (provider as any).once("display_uri", (uri: string) => { window.location.href = uri; }); } else { // Desktop: Show QR code setModalState("walletconnect-qr"); } } else { // Injected wallet flow setModalState("connecting"); } connect({ connector }); }, [connect] );

Interaction Patterns

The modal supports multiple dismissal methods to accommodate different user preferences and device types:

Click Outside: Users can tap the backdrop area to close the modal, following standard modal interaction patterns.

Close Button: A prominent × button in the top-right corner provides explicit dismissal control.

Swipe Gesture: On touch devices, users can swipe left to dismiss the modal, enhancing mobile usability:

const swipeHandlers = useSwipeable({ onSwipedLeft: () => onClose(), preventScrollOnSwipe: true, delta: { left: 50 }, swipeDuration: 300, });

Automatic Closure: The modal automatically closes upon successful connection, streamlining the user flow.

Props Reference

PropTypeRequiredDescription
isOpenbooleanYesControls the modal’s visibility. When true, the modal renders with animation. When false, the modal unmounts from the DOM.
onClose() => voidYesCallback function invoked when the modal should close. Called on backdrop click, close button click, swipe gesture, or successful connection.

CSS Architecture

The modal’s styling architecture creates distinct visual states while maintaining smooth transitions between them.

State-Based Modal Sizing

The modal dynamically adjusts its size based on the current state:

/* Default state - full featured */ .modal { width: 420px; max-width: 90vw; } /* Loading states - compact */ .modalLoading { width: 300px; max-width: 90vw; padding: 3rem 2rem; }

This adaptive sizing provides focused interfaces for each state while maintaining visual consistency.

Animation System

The modal implements a sophisticated animation system with multiple layers:

/* Backdrop fade */ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* Modal entrance */ @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -45%); } to { opacity: 1; transform: translate(-50%, -50%); } } /* QR code appearance */ @keyframes qrFadeIn { from { opacity: 0; } to { opacity: 1; } }

These layered animations create a polished appearance that guides user attention appropriately.

Brand Integration

The modal incorporates RitoSwap’s visual identity through consistent use of brand colors, the prominent logo display, and the customized QR code styling that uses the accent color (red) for the QR pattern while embedding the RitoSwap logo in the center.

Usage Examples

Basic Implementation with ConnectButton

import ConnectButton from '@/components/utilities/wallet/connectButton/ConnectButton'; import ConnectModal from '@/components/utilities/wallet/connectModal/ConnectModal'; function Navigation() { const [isConnectModalOpen, setIsConnectModalOpen] = useState(false); return ( <> <ConnectButton onClick={() => setIsConnectModalOpen(true)} /> <ConnectModal isOpen={isConnectModalOpen} onClose={() => setIsConnectModalOpen(false)} /> </> ); }

Custom Trigger Implementation

// Any component can trigger the modal function CustomConnectTrigger() { const [showModal, setShowModal] = useState(false); return ( <> <button onClick={() => setShowModal(true)} className={styles.customTrigger} > Connect to Web3 </button> <ConnectModal isOpen={showModal} onClose={() => setShowModal(false)} /> </> ); }

Integration with Auth Flow

// Using with authentication requirements function ProtectedSection() { const { isConnected } = useAccount(); const [showConnectModal, setShowConnectModal] = useState(false); useEffect(() => { if (!isConnected) { setShowConnectModal(true); } }, [isConnected]); return ( <> <ConnectModal isOpen={showConnectModal && !isConnected} onClose={() => setShowConnectModal(false)} /> {isConnected && <ProtectedContent />} </> ); }

Best Practices

When implementing the Connect Modal, ensure proper state management in the parent component. The modal itself is stateless for visibility control and relies entirely on props, making it predictable and easy to test.

Consider the user journey when deciding when to trigger the modal. While it can be opened proactively for protected sections, avoid showing it immediately on page load as this can be jarring for users who are simply browsing.

Test the modal behavior across different wallet types and connection methods. The experience differs significantly between injected wallets (MetaMask extension) and WalletConnect flows, particularly on mobile devices where deep linking behavior varies by browser and wallet app.

Monitor connection success rates in production. Understanding which wallets users prefer and where connections fail helps optimize the wallet options presented and can inform decisions about which providers to prioritize in the interface.

The Connect Modal’s automatic detection of wallet providers through EIP-6963 ensures that new wallets can integrate with RitoSwap without any code changes. As the Web3 wallet ecosystem evolves, the modal will automatically display newly available options, future-proofing the connection experience.