Skip to content
wyllet
  • Docs
  • Features
  • Playground
  • Blog
  • Docs
  • Features
  • Playground
  • Blog
  • Compare
  • Changelog
GitHub @wylletdevnpm Support
esc
  • IntroductionWhat Wyllet is, what it includes, and how it fits into a wagmi + viem dApp.
  • InstallationInstall Wyllet and its peer dependencies, and enable WalletConnect.
  • Quick startAdd a working connect button to a React dApp in a few minutes.
  • Next.jsUse Wyllet with the Next.js App Router, server components and SSR.
  • Build with AI assistantsGive Cursor, Claude Code, Copilot or ChatGPT the Wyllet docs and the rules for a correct integration.
  • ConfigurationCreate a wagmi config with getDefaultConfig: app info, chains, transports and wallets.
  • WylletProviderEvery WylletProvider prop: theme, appearance, tokens, auth, messages and callbacks.
  • WylletButtonThe Island button, its display options, and building your own trigger with useWylletButton.
Overview

Getting started

  • Introduction
  • Installation
  • Quick start
  • Next.js
  • Build with AI assistants

Core concepts

  • Configuration
  • WylletProvider
  • WylletButton
  • Presentations

Customization

  • Theming
  • Class names
  • Translations

Wallets

  • Wallets
  • All wallets
  • WalletConnect

Chains and tokens

  • Chains
  • Tokens

Features

  • Account panel
  • Activity and transactions
  • Toasts
  • Sign-In With Ethereum
  • ConnectGate

Reference

  • Hooks
  • Components
  • Utilities and types

Guides

  • Security
  • Migrate from RainbowKit
  • FAQ
wyllet

The open-source wallet connector for React dApps. Built on wagmi and viem.

MIT licensed. v1.1.0 on npm with provenance.

Product

  • Features
  • Compare
  • Playground
  • Changelog
  • Blog

Docs

  • Quick start
  • Next.js
  • Build with AI
  • Theming
  • Migrate from RainbowKit

Community

  • GitHub
  • X @wylletdev
  • npm
  • Releases
  • Report an issue

Support

  • support@wyllet.dev
  • FAQ
  • Security
  • Report a vulnerability
  • MIT License

For AI agents

  • llms.txt
  • llms-full.txt
  • RSS feed
  • Sitemap

Wallet, network and token names and logos are trademarks of their respective owners and are used only to identify them.

Docs/Guides

Migrate from RainbowKit

Map RainbowKit concepts to Wyllet and switch a dApp over step by step.

View .mdReport a problem

RainbowKit and Wyllet solve the same problem on the same foundation: both sit on top of wagmi, viem and react-query, and both give you a provider, a connect button and a config helper. Most of a migration is renaming. This guide maps RainbowKit's concepts to Wyllet's, walks through the switch step by step, and lists what works differently. For a side-by-side of features, licenses and dependencies, see How Wyllet compares.

Note

Wyllet requires wagmi v3 and viem 2. If your app is still on an older wagmi major, upgrade wagmi first using wagmi's own migration guide, then switch the connect layer.

Concept map

RainbowKitWyllet
RainbowKitProviderWylletProvider
ConnectButtonWylletButton
ConnectButton.CustomuseWylletButton()
getDefaultConfiggetDefaultConfig (same idea, walletConnectProjectId instead of projectId)
darkTheme() / lightTheme()obsidianTheme() / porcelainTheme() (also auroraTheme(), terminalTheme())
useConnectModal().openConnectModaluseWyllet().openConnect
useAccountModal().openAccountModaluseWyllet().openAccount
useChainModal().openChainModaluseWyllet().openTab('networks')
RainbowKitAuthenticationProvider + adapterauth prop on WylletProvider
Custom wallet objectsWallet objects
Wallet groups (groupName)A flat wallets array
useAddRecentTransactionuseWylletActivity().addTransaction
import '@rainbow-me/rainbowkit/styles.css'Not needed (styles are injected)

Step by step

1. Swap the packages

npm uninstall @rainbow-me/rainbowkit
npm install wyllet
 
# Only if you use WalletConnect (QR codes and mobile wallets):
npm install @walletconnect/ethereum-provider

Wyllet's peers are react, react-dom, wagmi, viem and @tanstack/react-query, which your app already has. @walletconnect/ethereum-provider is an optional peer you install and pin yourself.

2. Update the config

Wyllet's getDefaultConfig takes the same kind of input and returns a wagmi config. Rename projectId to walletConnectProjectId. Other wagmi createConfig options, such as ssr, pass straight through.

Before
import { getDefaultConfig } from '@rainbow-me/rainbowkit'
import { base, mainnet } from 'wagmi/chains'
 
export const config = getDefaultConfig({
  appName: 'My dApp',
  projectId: 'YOUR_PROJECT_ID',
  chains: [mainnet, base],
  ssr: true,
})
After
import { getDefaultConfig } from 'wyllet'
import { base, mainnet } from 'viem/chains'
 
export const config = getDefaultConfig({
  appName: 'My dApp',
  walletConnectProjectId: 'YOUR_PROJECT_ID',
  chains: [mainnet, base],
  ssr: true,
})

Wyllet's getDefaultConfig also accepts appDescription, appUrl, appIcon, transports, wallets and extra connectors. See Configuration.

3. Replace the provider

Keep WagmiProvider and QueryClientProvider as they are. Replace RainbowKitProvider with WylletProvider and delete the RainbowKit stylesheet import.

app/providers.tsx
'use client'
 
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { WylletProvider } from 'wyllet'
import { config } from './wagmi'
 
const queryClient = new QueryClient()
 
export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <WylletProvider>{children}</WylletProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}

A few RainbowKit provider props have direct counterparts:

RainbowKit propWyllet
themetheme (a theme, or a { light, dark } pair)
appInfo.appNameappName in getDefaultConfig, or appInfo.name on the provider
appInfo.learnMoreUrlappInfo.learnMoreUrl
appInfo.disclaimerdisclaimer
avataravatar (receives address, ensImage and size)
localemessages (override any string; see Translations)
initialChainThe first chain in your config is the default

4. Replace the button

// Before
<ConnectButton label="Sign in" />
 
// After
<WylletButton label="Sign in" />

WylletButton has a display prop instead of accountStatus and showBalance: 'full' shows the avatar, name and balance, 'compact' the avatar and name, and 'avatar' the avatar only. The network appears as a badge on the avatar, so there is no separate chain button. See WylletButton.

5. Replace custom buttons

ConnectButton.Custom is a render prop. Wyllet uses a hook instead, so you can call it in any component.

import { useWylletButton } from 'wyllet'
 
function CustomButton() {
  const { mounted, account, chain, openConnect, openAccount } = useWylletButton()
  if (!mounted) return null
  if (!account) return <button onClick={(e) => openConnect(e.currentTarget)}>Connect</button>
  if (chain?.unsupported) return <button onClick={(e) => openAccount(e.currentTarget, 'networks')}>Wrong network</button>
  return <button onClick={(e) => openAccount(e.currentTarget)}>{account.displayName}</button>
}
ConnectButton.CustomuseWylletButton()
mountedmounted
account.displayNameaccount.displayName
account.displayBalanceaccount.balance.formatted and account.balance.symbol
chain.unsupportedchain.unsupported
openConnectModal()openConnect(anchor?)
openAccountModal()openAccount(anchor?)
openChainModal()openAccount(anchor, 'networks')
authenticationStatusauthStatus

Passing the clicked element as anchor lets the popover presentation position itself next to your button.

6. Replace the modal hooks

const { openConnect, openAccount, openTab, close } = useWyllet()
 
openConnect()          // was openConnectModal()
openAccount()          // was openAccountModal()
openTab('networks')    // was openChainModal()

7. Move the theme

// Before
<RainbowKitProvider theme={darkTheme({ accentColor: '#7b3fe4', accentColorForeground: 'white' })} />
 
// After
<WylletProvider theme={obsidianTheme({ accentColor: '#7b3fe4', accentColorForeground: 'white' })} />

accentColor and accentColorForeground keep their names. The other knobs differ: radius takes 'sharp' | 'soft' | 'round' | 'pill', overlayBlur takes 'none' | 'subtle' | 'heavy', and fontFamily takes any font stack. To follow the OS color scheme, pass a pair:

<WylletProvider theme={{ light: porcelainTheme(), dark: obsidianTheme() }} colorMode="auto" />

Every token is also a CSS variable (such as --wy-colors-accent), and the classNames prop attaches your own classes to individual elements. See Theming and Class names.

8. Move authentication

In RainbowKit you wrap the app in RainbowKitAuthenticationProvider, pass an adapter, and supply the authentication status yourself. In Wyllet you pass an adapter to the auth prop and Wyllet tracks the status.

import type { WylletAuthAdapter } from 'wyllet'
 
const auth: WylletAuthAdapter = {
  getNonce: () => fetch('/api/nonce').then((r) => r.text()),
  verify: ({ message, signature }) =>
    fetch('/api/verify', { method: 'POST', body: JSON.stringify({ message, signature }) }).then((r) => r.ok),
  signOut: () => fetch('/api/logout', { method: 'POST' }).then(() => {}),
  getSession: () => fetch('/api/me').then((r) => (r.ok ? r.json() : null)),
}
 
<WylletProvider auth={auth}>{children}</WylletProvider>
  • createMessage is optional. By default Wyllet builds an EIP-4361 message with viem/siwe.
  • getSession restores an existing session on page load. Return { address } or null.
  • Disconnecting or switching accounts calls signOut.
  • Read the status with useWylletAuth().

Your backend nonce and verify endpoints do not need to change. See Sign-In With Ethereum.

9. Move the wallet list

RainbowKit groups wallets under a groupName. Wyllet takes one ordered array of called presets, and groups wallets in the UI on its own: detected and recently used first, then the rest.

Before
wallets: [{ groupName: 'Recommended', wallets: [metaMaskWallet, rainbowWallet, walletConnectWallet] }]
After
import { metaMaskWallet, rainbowWallet, walletConnectWallet } from 'wyllet'
 
wallets: [metaMaskWallet(), rainbowWallet(), walletConnectWallet()]

Wallets with featured: false are listed in a lower group. Installed browser wallets you did not list are still detected through EIP-6963. Wyllet bundles official artwork only for its default wallets (MetaMask, Phantom, Rabby, OKX and WalletConnect). coinbaseWallet(), rainbowWallet() and trustWallet() show a neutral monogram unless the extension is installed or you pass an icon through overrides. See Wallets.

10. Port custom wallets

A custom wallet is a plain object. The main renames are iconUrl to icon and the mobile WalletConnect link to walletConnect.mobileUri.

import type { Wallet } from 'wyllet'
 
const acme: Wallet = {
  id: 'acme',
  name: 'Acme',
  icon: 'https://acme.xyz/icon.png',
  iconBackground: '#ffffff',
  rdns: 'xyz.acme',
  walletConnect: { mobileUri: (uri) => `acme://wc?uri=${encodeURIComponent(uri)}` },
  downloadUrls: { browserExtension: 'https://acme.xyz/download', ios: '…', android: '…' },
}

To give a wallet a dedicated wagmi connector, set createConnector to a function that takes no arguments and returns a wagmi CreateConnectorFn.

11. Move recent transactions

const { addTransaction } = useWylletActivity()
 
const hash = await writeContractAsync({ /* ... */ })
addTransaction({ hash, description: 'Mint 1 NFT' })

There is no showRecentTransactions flag. Transactions appear in the account panel's Activity tab, with pending and confirmed toasts. See Activity and transactions.

What works differently

  • Presentations. The panel opens as a side drawer by default. Set appearance.presentation to 'popover' to anchor it to the button, or 'modal' for a centered dialog. Phones get a draggable bottom sheet. See Presentations.
  • Activity. The Activity tab records connects, disconnects, network switches and sign-ins as well as transactions, and you can add your own entries with log. Pending transactions are watched again after a reload.
  • Toasts. useWylletToast() gives you themed, promise-aware notifications that match the panel. See Toasts.
  • Tokens. The account panel has a Tokens tab with balances for a token list you define in code, with pinning, sorting and optional user import. See Tokens.
  • Networks. Switching networks happens in the account panel's Networks tab, which also shows the live gas price and a wrong-network banner.
  • Gating. ConnectGate renders content only when the user is connected, on a supported network and signed in. See ConnectGate.
  • All wallets. With a WalletConnect project id, the WalletConnect option opens a searchable directory of wallets from the WalletConnect registry, and each opens its own app on phones. See All wallets.
  • Styles. Wyllet injects its CSS, so there is no stylesheet import. Set injectStyles={false} and import wyllet/styles.css if you want to load it yourself.
  • Keyboard. Set shortcut="mod+k" to toggle the panel from the keyboard. In the wallet list, arrow keys move and number keys pick a wallet.
  • Dependencies. Wyllet has no third-party runtime dependencies. See Security.

Checklist

  • @rainbow-me/rainbowkit removed from package.json and the lockfile.
  • The RainbowKit stylesheet import removed.
  • projectId renamed to walletConnectProjectId.
  • @walletconnect/ethereum-provider installed if you use WalletConnect.
  • Every ConnectButton, ConnectButton.Custom and modal hook replaced.
  • The auth adapter moved to the auth prop, with getSession if you restore sessions.
  • Your app still connects, switches networks and signs in. Try it in the playground first if you want to compare settings.
PreviousSecurityNextFAQ

On this page

  • Concept map
  • Step by step
  • 1. Swap the packages
  • 2. Update the config
  • 3. Replace the provider
  • 4. Replace the button
  • 5. Replace custom buttons
  • 6. Replace the modal hooks
  • 7. Move the theme
  • 8. Move authentication
  • 9. Move the wallet list
  • 10. Port custom wallets
  • 11. Move recent transactions
  • What works differently
  • Checklist