Network Modal
- NetworkModal.tsx
- NetworkModal.module.css
- NetworkWidget.tsx
Overview
The Network Modal serves as the primary interface for blockchain network selection within the RitoSwap ecosystem. This modal component provides users with a visually rich selection interface displaying all configured networks with their respective logos and names. As part of the Wallet UI widget collection, the modal offers an intuitive way to switch between different blockchain networks while maintaining awareness of the currently active chain through visual highlighting.

Built on Wagmi v2’s network switching capabilities, the Network Modal orchestrates chain selection with immediate visual feedback and smooth transitions. The component integrates deeply with RitoSwap’s Chain Info Provider system to transform technical chain identifiers into recognizable blockchain brands through logo display and name normalization. This modal can be triggered by any component that manages its open state, most commonly through the NetworkWidget or the AccountModal.
Component Architecture
The Network Modal demonstrates sophisticated integration between Wagmi’s chain switching functionality and user interface design principles. 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 Network Modal itself is a controlled component that responds to external state management, it’s most commonly triggered by the NetworkWidget component. When users click the NetworkWidget, it updates its internal state to open the modal:

// In NetworkWidget.tsx
const [isModalOpen, setIsModalOpen] = useState(false);
// Clicking the widget opens the modal
<div onClick={() => setIsModalOpen(true)}>
{/* Widget content */}
</div>
// Modal receives state through props
<NetworkModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
/>
This architecture ensures the modal remains decoupled from its triggers, allowing any component to control its visibility through simple boolean state management.
Integration with Chain Info Provider
The Network Modal leverages the Chain Info Provider system to enhance Wagmi’s technical blockchain data with visual assets and user-friendly naming. While Wagmi provides the list of configured chains and switching functionality, it lacks the visual elements necessary for intuitive network selection.
The component accesses the Chain Info Provider through the useLogo
hook:
const {
getChainLogoUrl,
getFallbackLogoUrl,
getChainDisplayName
} = useLogo();
This integration enables the modal to display blockchain logos fetched from TrustWallet’s CDN, with intelligent fallback handling when assets are unavailable. The Chain Info Provider manages the complexity of CDN URL construction, special case handling for chains with non-standard naming conventions, and custom chain support for local development networks. For comprehensive documentation on the Chain Info Provider’s capabilities and configuration options, refer to the Chain Info Provider documentation.
Portal Rendering Strategy
The Network 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.
Visual Design and Functionality
The Network Modal implements a clean, focused design that emphasizes clarity and ease of selection. The interface presents blockchain networks in a vertically scrollable list, with each network displayed as a pill-shaped button containing the chain’s logo and name.
Active Chain Highlighting
The modal automatically identifies and visually highlights the currently active chain, always positioning it at the top of the list for immediate recognition. This design decision reduces cognitive load by clearly distinguishing the current network from available alternatives:
const sortedChains = [...chains].sort((a, b) => {
if (a.id === activeChain?.id) return -1;
if (b.id === activeChain?.id) return 1;
return 0;
});
Active chains receive distinct visual treatment through background color changes, creating a clear hierarchy within the selection interface.
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,
});
Network Selection: Clicking any network button triggers an immediate chain switch and closes the modal, providing instant feedback.
Visual Hierarchy and Scrolling
The modal implements a sophisticated visual structure with three distinct sections:
Header Section: Contains the modal title and close button, remaining fixed during scrolling.
Scrollable Content: The network list scrolls independently when content exceeds viewport height, with custom scrollbar styling that matches the application’s design language.
Bottom Gradient: A subtle gradient overlay at the bottom provides visual indication of additional content below the fold, enhancing discoverability of networks lower in the list.
Technical Implementation
Wagmi v2 Hook Integration
The Network Modal leverages essential Wagmi v2 hooks to manage network selection and switching:
useAccount
provides connection status and the currently active chain. The component uses these values to highlight the active network and automatically close if the user disconnects their wallet during interaction.
useConfig
supplies the complete list of configured chains available for selection. This ensures the modal always displays the current configuration without manual updates.
useSwitchChain
provides the network switching functionality. The hook returns a switchChain
function that accepts a chain ID and handles all network change operations:
const { switchChain } = useSwitchChain();
// Network button click handler
onClick={() => {
switchChain({ chainId: chain.id });
onClose();
}}
State Management and Effects
The modal implements careful state coordination to ensure proper behavior across different scenarios:
useEffect(() => {
if (!isConnected && isOpen) onClose();
}, [isConnected, isOpen, onClose]);
This effect ensures the modal automatically closes if the user disconnects their wallet while it’s open, preventing confusing states where network selection would be meaningless.
Error Handling and Fallbacks
The modal implements comprehensive error handling for logo loading failures:
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = getFallbackLogoUrl();
}}
This two-tier system first attempts to load chain-specific logos from the CDN, then falls back to a generic placeholder if loading fails. The error handler prevents infinite retry loops by nullifying the error handler after the first failure.
Props Reference
Prop | Type | Required | Description |
---|---|---|---|
isOpen | boolean | Yes | Controls the modal’s visibility. When true, the modal renders with animation. When false, the modal unmounts from the DOM. |
onClose | () => void | Yes | Callback function invoked when the modal should close. Called on backdrop click, close button click, swipe gesture, or network selection. |
CSS Architecture
The modal’s styling architecture creates a layered visual experience with careful attention to animation and responsiveness.
Backdrop and Blur Effects
The backdrop creates a semi-transparent overlay with backdrop blur, focusing user attention on the modal content:
.backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
z-index: 2000;
animation: fadeIn 0.2s ease-out;
}
The blur effect creates depth and maintains visual connection to the underlying interface while clearly delineating the modal interaction space.
Animation System
The modal implements a two-stage animation system. The backdrop fades in quickly to provide immediate feedback, while the modal content slides in with a subtle upward motion:
@keyframes slideIn {
from {
opacity: 0;
transform: translate(-50%, -45%);
}
to {
opacity: 1;
transform: translate(-50%, -50%);
}
}
This creates a smooth, professional appearance that enhances the perception of interface responsiveness.
Responsive Design
The modal adapts to different viewport sizes while maintaining usability:
.modal {
width: 400px;
max-width: 90vw;
max-height: 80vh;
}
@media (max-width: 480px) {
.modal {
width: 95vw;
}
}
On mobile devices, the modal expands to use available screen width while maintaining appropriate padding for touch targets.
Usage Examples
Basic Implementation with NetworkWidget
import NetworkWidget from '@/components/utilities/wallet/network/NetworkWidget';
import NetworkModal from '@/components/utilities/wallet/network/NetworkModal';
function Navigation() {
const [isNetworkModalOpen, setIsNetworkModalOpen] = useState(false);
return (
<>
<div onClick={() => setIsNetworkModalOpen(true)}>
<NetworkWidget />
</div>
<NetworkModal
isOpen={isNetworkModalOpen}
onClose={() => setIsNetworkModalOpen(false)}
/>
</>
);
}
Custom Trigger Implementation
// Any component can trigger the modal
function CustomNetworkSelector() {
const [showModal, setShowModal] = useState(false);
return (
<>
<button
onClick={() => setShowModal(true)}
className={styles.customTrigger}
>
Change Network
</button>
<NetworkModal
isOpen={showModal}
onClose={() => setShowModal(false)}
/>
</>
);
}
Integration with Global State
// Using with state management libraries
function AppWithNetworkModal() {
const { isNetworkModalOpen, closeNetworkModal } = useAppState();
return (
<NetworkModal
isOpen={isNetworkModalOpen}
onClose={closeNetworkModal}
/>
);
}
Best Practices
When implementing the Network Modal, ensure proper state management in the parent component. The modal itself is stateless and relies entirely on props for visibility control, making it predictable and easy to test.
Configure chain information in the Chain Info Provider for all networks your application supports. This ensures logos display correctly and chain names appear in user-friendly formats. Missing configuration will result in fallback placeholders that diminish the user experience.
Test the modal behavior across different viewport sizes and devices. The swipe-to-dismiss gesture should feel natural on mobile devices without interfering with vertical scrolling of the network list.
Monitor network switching performance in production. While Wagmi handles the technical aspects of chain switching, understanding typical switching times helps set appropriate user expectations through loading states or notifications.
The Network Modal’s automatic positioning of the active chain at the top of the list reduces the time users spend searching for their current network. This design decision becomes particularly valuable in applications supporting many chains, where finding the active network in an unsorted list could create friction in the user experience.